当前位置: 首页 > 编程日记 > 正文

OpenCV 【十八】图像平滑处理/腐蚀与膨胀(Eroding and Dilating)/开闭运算,形态梯度,顶帽,黑帽运算

图像滤波总结(面试经验总结)https://blog.csdn.net/Darlingqiang/article/details/79507468

目录

part one 图像平滑处理

1原理

2代码

3效果

part two 腐蚀与膨胀(Eroding and Dilating)

1原理

2代码

3运行结果

part three更多形态学变换¶

1 原理

2 代码

3 结果


part one 图像平滑处理

1原理

  • 平滑 也称 模糊, 是一项简单且使用频率很高的图像处理方法。

  • 平滑处理的用途有很多, 但是在本教程中我们仅仅关注它减少噪声的功用 (其他用途在以后的教程中会接触到)。

  • 平滑处理时需要用到一个 滤波器 。 最常用的滤波器是 线性 滤波器,线性滤波处理的输出像素值 (i.e. g(i,j)) 是输入像素值 (i.e. f(i+k,j+l))的加权和 :

    g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l)

    h(k,l) 称为 , 它仅仅是一个加权系数。

    不妨把 滤波器 想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口滑过图像。

  • 滤波器的种类有很多, 这里仅仅提及最常用的:

1.1归一化块滤波器 (Normalized Box Filter)

  • 最简单的滤波器, 输出像素值是核窗口内像素值的 均值 ( 所有像素加权系数相等)

  • 核如下:

    K = \dfrac{1}{K_{width} \cdot K_{height}} \begin{bmatrix}     1 & 1 & 1 & ... & 1 \\     1 & 1 & 1 & ... & 1 \\     . & . & . & ... & 1 \\     . & . & . & ... & 1 \\     1 & 1 & 1 & ... & 1    \end{bmatrix}

1.2高斯滤波器 (Gaussian Filter)

  • 最有用的滤波器 (尽管不是最快的)。 高斯滤波是将输入数组的每一个像素点与 高斯内核 卷积将卷积和当作输出像素值。

  • 还记得1维高斯函数的样子吗?

    假设图像是1维的,那么观察上图,不难发现中间像素的加权系数是最大的, 周边像素的加权系数随着它们远离中间像素的距离增大而逐渐减小。

Note

2维高斯函数可以表达为 :

G_{0}(x, y) = A  e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } +  \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } }

其中 \mu 为均值 (峰值对应位置), G_{0}(x, y) = A  e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } +  \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } }

代表标准差 (变量 x 和 变量 y 各有一个均值,也各有一个标准差)

1.3中值滤波器 (Median Filter)

中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的 中值 代替 。

1.4双边滤波 (Bilateral Filter)

  • 目前我们了解的滤波器都是为了 平滑 图像, 问题是有些时候这些滤波器不仅仅削弱了噪声, 连带着把边缘也给磨掉了。 为避免这样的情形 (至少在一定程度上 ), 我们可以使用双边滤波。

  • 类似于高斯滤波器,双边滤波器也给每一个邻域像素分配一个加权系数。 这些加权系数包含两个部分, 第一部分加权方式与高斯滤波一样,第二部分的权重则取决于该邻域像素与当前像素的灰度差值。

  • 详细的解释可以查看 链接

2代码

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
​
using namespace std;
using namespace cv;
​
/// 全局变量
int DELAY_CAPTION = 15000;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
​
Mat src; Mat dst;
char window_name[] = "Filter Demo 1";
​
/// 函数申明
int display_caption(char* caption);
int display_dst(int delay);
​
/**
*  main 函数
*/
int main(int argc, char** argv)
{namedWindow(window_name, CV_WINDOW_AUTOSIZE);
​/// 载入原图像src = imread("C:\\Users\\guoqi\\Desktop\\ch7\\4.jpg", 1);
​if (display_caption("Original Image") != 0) { return 0; }
​dst = src.clone();if (display_dst(DELAY_CAPTION) != 0) { return 0; }/// 使用 均值平滑if (display_caption("Homogeneous Blur") != 0) { return 0; }
​for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2){blur(src, dst, Size(i, i), Point(-1, -1));if (display_dst(DELAY_BLUR) != 0) { return 0; }}
​/// 使用高斯平滑if (display_caption("Gaussian Blur") != 0) { return 0; }
​for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2){GaussianBlur(src, dst, Size(i, i), 0, 0);if (display_dst(DELAY_BLUR) != 0) { return 0; }}
​/// 使用中值平滑if (display_caption("Median Blur") != 0) { return 0; }
​for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2){medianBlur(src, dst, i);if (display_dst(DELAY_BLUR) != 0) { return 0; }}
​/// 使用双边平滑if (display_caption("Bilateral Blur") != 0) { return 0; }
​for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2){bilateralFilter(src, dst, i, i * 2, i / 2);if (display_dst(DELAY_BLUR) != 0) { return 0; }}
​/// 等待用户输入display_caption("End: Press a key!");
​waitKey(0);return 0;
}
​
int display_caption(char* caption)
{dst = Mat::zeros(src.size(), src.type());putText(dst, caption,Point(src.cols / 4, src.rows / 2),CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255));
​imshow(window_name, dst);int c = waitKey(DELAY_CAPTION);if (c >= 0) { return -1; }return 0;
}
​
int display_dst(int delay)
{imshow(window_name, dst);int c = waitKey(delay);if (c >= 0) { return -1; }return 0;
}

createTrackbar 的使用

#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
​
using namespace std;
using namespace cv;
//拖动条回调函数
void onChangeTrackBar(int pos, void *data)
{//强制类型转换Mat srcImage = *(cv::Mat*)(data);Mat dstImage;//根据拖动条的值对传入图像进行二值化threshold(srcImage, dstImage, pos, 255, 0);imshow("threshold", dstImage);
}
int main()
{//读取图像Mat srcImage = imread("C:\\Users\\guoqi\\Desktop\\ch7\\1.jpg", IMREAD_UNCHANGED);if (!srcImage.data) {cout << "read failed" << endl;system("pause");return -1;}//原图像转换灰度图Mat srcGray;cvtColor(srcImage, srcGray, CV_RGB2GRAY);namedWindow("threshold");//创建窗口imshow("threshold", srcGray);//创建滑动条createTrackbarcreateTrackbar("pos", "threshold",0, 255, onChangeTrackBar, &srcImage);waitKey(0);return 0;
}

3效果

part two 腐蚀与膨胀(Eroding and Dilating)

1原理

1.1形态学操作¶

  • 简单讲,形态学操作就是基于形状的一系列图像处理操作。将 结构元素 作用于输入图像来产生输出图像。

  • 最基本的形态学操作有二:腐蚀与膨胀(Erosion 与 Dilation)。 他们的运用广泛:

    • 消除噪声

    • 分割(isolate)独立的图像元素,以及连接(join)相邻的元素。

    • 寻找图像中的明显的极大值区域或极小值区域。

  • 通过以下图像,我们简要来讨论一下膨胀与腐蚀操作(译者注:注意这张图像中的字母为黑色,背景为白色,而不是一般意义的背景为黑色,前景为白色):

  • Original image

  • 1.2膨胀

    • 此操作将图像 A 与任意形状的内核 (B),通常为正方形或圆形,进行卷积。

    • 内核 B 有一个可定义的 锚点, 通常定义为内核中心点。

    • 进行膨胀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。对上图采用膨胀操作我们得到:

      Dilation result - Theory example

    背景(白色)膨胀,而黑色字母缩小了。

    1.3腐蚀

    • 腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。

    • 进行腐蚀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最小相素值提取,并代替锚点位置的相素。

    • 以与膨胀相同的图像作为样本,我们使用腐蚀操作。从下面的结果图我们看到亮区(背景)变细,而黑色区域(字母)则变大了。

      Erosion result - Theory example

2代码

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h>
​
using namespace cv;
​
/// 全局变量
Mat src, erosion_dst, dilation_dst;
​
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;
​
/** Function Headers */
void Erosion(int, void*);
void Dilation(int, void*);
​
/** @function main */
int main(int argc, char** argv)
{/// Load 图像src = imread("C:\\Users\\guoqi\\Desktop\\ch7\\1.jpg", IMREAD_UNCHANGED);
​if (!src.data){return -1;}
​/// 创建显示窗口namedWindow("Erosion Demo", CV_WINDOW_AUTOSIZE);namedWindow("Dilation Demo", CV_WINDOW_AUTOSIZE);cvMoveWindow("Dilation Demo", src.cols, 0);
​/// 创建腐蚀 TrackbarcreateTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",&erosion_elem, max_elem,Erosion);
​createTrackbar("Kernel size:\n 2n +1", "Erosion Demo",&erosion_size, max_kernel_size,Erosion);
​/// 创建膨胀 TrackbarcreateTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",&dilation_elem, max_elem,Dilation);
​createTrackbar("Kernel size:\n 2n +1", "Dilation Demo",&dilation_size, max_kernel_size,Dilation);
​/// Default startErosion(0, 0);Dilation(0, 0);
​waitKey(0);return 0;
}
​
/**  @function Erosion  */
void Erosion(int, void*)
{int erosion_type;if (erosion_elem == 0) { erosion_type = MORPH_RECT; }else if (erosion_elem == 1) { erosion_type = MORPH_CROSS; }else if (erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
​Mat element = getStructuringElement(erosion_type,Size(2 * erosion_size + 1, 2 * erosion_size + 1),Point(erosion_size, erosion_size));
​/// 腐蚀操作erode(src, erosion_dst, element);imshow("Erosion Demo", erosion_dst);
}
​
/** @function Dilation */
void Dilation(int, void*)
{int dilation_type;if (dilation_elem == 0) { dilation_type = MORPH_RECT; }else if (dilation_elem == 1) { dilation_type = MORPH_CROSS; }else if (dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
​Mat element = getStructuringElement(dilation_type,Size(2 * dilation_size + 1, 2 * dilation_size + 1),Point(dilation_size, dilation_size));///膨胀操作dilate(src, dilation_dst, element);imshow("Dilation Demo", dilation_dst);
}

3运行结果

part three更多形态学变换¶

这篇文档将会简要介绍OpenCV提供的5种高级形态学操作:

1 原理

1.1开运算 (Opening)

开运算是通过先对图像先腐蚀再膨胀实现的。

dst = open( src, element) = dilate( erode( src, element ) )

  • 能够排除小团块物体(假设物体较背景明亮)

  • 请看下面,左图是原图像,右图是采用开运算转换之后的结果图。 观察发现字母拐弯处的白色空间消失。

    Opening

1.2闭运算(Closing)

  • 闭运算是通过先对图像先膨胀再腐蚀实现的。

    dst = close( src, element ) = erode( dilate( src, element ) )

  • 能够排除小型黑洞(黑色区域)。

    Closing example

1.3形态梯度(Morphological Gradient)

  • 膨胀图与腐蚀图之差

    dst = morph_{grad}( src, element ) = dilate( src, element ) - erode( src, element )

  • 能够保留物体的边缘轮廓,如下所示:

    Gradient

1.4顶帽(Top Hat)

  • 原图像与开运算结果图之差

    dst = tophat( src, element ) = src - open( src, element )

    Top Hat

1.5黑帽(Black Hat)

  • 闭运算结果图与原图像之差

    dst = blackhat( src, element ) = close( src, element ) - src

    Black Hat

2 代码

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
​
using namespace cv;
​
/// 全局变量
Mat src, dst;
​
int morph_elem = 0;
int morph_size = 0;
int morph_operator = 0;
int const max_operator = 4;
int const max_elem = 2;
int const max_kernel_size = 21;
​
char* window_name = "Morphology Transformations Demo";
​
/** 回调函数申明 */
void Morphology_Operations(int, void*);
​
/** @函数 main */
int main(int argc, char** argv)
{/// 装载图像src = imread("C:\\Users\\guoqi\\Desktop\\ch7\\7.jpg", IMREAD_UNCHANGED);
​if (!src.data){return -1;}
​/// 创建显示窗口namedWindow(window_name, CV_WINDOW_AUTOSIZE);
​/// 创建选择具体操作的 trackbarcreateTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations);
​/// 创建选择内核形状的 trackbarcreateTrackbar("Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,&morph_elem, max_elem,Morphology_Operations);
​/// 创建选择内核大小的 trackbarcreateTrackbar("Kernel size:\n 2n +1", window_name,&morph_size, max_kernel_size,Morphology_Operations);
​/// 启动使用默认值Morphology_Operations(0, 0);
​waitKey(0);return 0;
}
​
/**
* @函数 Morphology_Operations
*/
void Morphology_Operations(int, void*)
{// 由于 MORPH_X的取值范围是: 2,3,4,5 和 6int operation = morph_operator + 2;
​Mat element = getStructuringElement(morph_elem, Size(2 * morph_size + 1, 2 * morph_size + 1), Point(morph_size, morph_size));
​/// 运行指定形态学操作morphologyEx(src, dst, operation, element);imshow(window_name, dst);
}

看一下程序的总体流程:

  • 装载图像

  • 创建显示形态学操作的窗口

  • 创建3个trackbar获取用户参数:

    • 第一个trackbar “Operator” 返回用户选择的形态学操作类型 (morph_operator).

      createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat",window_name, &morph_operator, max_operator,Morphology_Operations );
    • 第二个trackbar “Element” 返回 morph_elem, 指定内核形状:

      createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,&morph_elem, max_elem,Morphology_Operations );
    • 第三个trackbar “Kernel Size” 返回内核大小(morph_size)

      createTrackbar( "Kernel size:\n 2n +1", window_name,&morph_size, max_kernel_size,Morphology_Operations );
  • 每当任一标尺被移动, 用户函数 Morphology_Operations 就会被调用,该函数获取trackbar的当前值运行指定操作并更新显示结果图像。

     /*** @函数 Morphology_Operations*/
    void Morphology_Operations( int, void* )
    {// 由于 MORPH_X的取值范围是: 2,3,4,5 和 6int operation = morph_operator + 2;
    ​Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
    ​/// 运行指定形态学操作morphologyEx( src, dst, operation, element );imshow( window_name, dst );}

    运行形态学操作的核心函数是 morphologyEx 。在本例中,我们使用了4个参数(其余使用默认值):

    • src : 原 (输入) 图像

    • dst: 输出图像

    • operation

      : 需要运行的形态学操作。 我们有5个选项:

      • ***Opening*: MORPH_OPEN : 2**

      • ***Closing*: MORPH_CLOSE: 3**

      • ***Gradient*: MORPH_GRADIENT: 4**

      • ***Top Hat*: MORPH_TOPHAT: 5**

      • ***Black Hat*: MORPH_BLACKHAT: 6**

    你可以看到, 它们的取值范围是 <2-6>, 因此我们要将从tracker获取的值增加(+2):

    int operation = morph_operator + 2;
    • element: 内核,可以使用函数:get_structuring_element:getStructuringElement <> 自定义。

3 结果

这里是显示窗口的两个截图。第一幅图显示了使用交错内核和 开运算 之后的结果, 第二幅图显示了使用椭圆内核和 黑帽 之后的结果。

椭圆内核和 黑帽 之后的结果。

相关文章:

第九章 大网高级 ASA 高级设置

url 过滤实验要求&#xff1a;1、 创建class-map 类映射&#xff0c;识别传输流量。2、 创建policy-map策略映射&#xff0c;关联class-map。3、 应用到policy-map到接口上。一、 配置接口地址二、 配置路由&#xff0c;网络互通三、 创建特权和vty 密码四、 验证网络互通五、 …

linux基础知识-链接列表

linux基础知识-链接列表 1. 安装centos 7 1.1 Linux的初识1.2 centOS 7安装教程1.3 centOS 7配置ip和网络问题排查1.4 PuTTY和Xshell远程连接与密钥认证登录1.5 单用户和救援模式2. 文件与目录管理 1.6 系统目录结构、文件类型及相关命令1.7 文件目录管理及相关的命令使用方法…

OpenCV 【十九】图像金字塔/基本的阈值操作/实现自己的线性滤波器

目录 1.part one 图像金字塔 1.1原理 1.1.1图像金字塔 1.1.2高斯金字塔 1.2代码 1.3运行结果 2.part two 基本的阈值操作 2.1原理 2.1.1阈值化的类型&#xff1a; 2.1.2阈值类型1&#xff1a;二进制阈值化 2.1.3阈值类型2&#xff1a;反二进制阈值化 2.1.4阈值类型…

Get started with ros -- 1

原创博文&#xff1a;转载请标明出处&#xff08;周学伟&#xff09;&#xff1a;http://www.cnblogs.com/zxouxuewei/tag/ 一.Introduction&#xff1a; 机器人操作系统&#xff08;ROS&#xff09;是使机器人系统的不同部分能够发现&#xff0c;发送和接收数据的通信接口。MA…

利用 createTrackbar 进行二值化

#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> //createTrackbar的回调响应函数 void onChangeTrackBar (int pos,void* data) {// 强制类型转换cv::Mat srcImage *(cv::Mat*)(data); cv:…

ASP.NET Core 2.2中的Endpoint路由

Endpoint路由 在ASP.NET Core 2.2中&#xff0c;新增了一种路由&#xff0c;叫做Endpoint&#xff08;终结点&#xff09;路由。本文将以往的路由系统称为传统路由。 本文通过源码的方式介绍传统路由和Endpoint路由部分核心功能和实现方法&#xff0c;具体功能上的差异见官方文…

OpenCV 【二十】给图像添加边界

目录 1原理 2 代码 3 运行结果 1原理 前一节我们学习了图像的卷积操作。一个很自然的问题是如何处理卷积边缘。当卷积点在图像边界时会发生什么&#xff0c;如何处理这个问题&#xff1f; 大多数用到卷积操作的OpenCV函数都是将给定图像拷贝到另一个轻微变大的图像中&#…

Linux账户安全管理--useradd、groupadd、passwd、chown、chmod工具

groupadd-g 设置组id号实例&#xff1a; groupadd tomcatgroupadd -g600 tomcat删除组用groupdelgroupdel tomcatuseradd-c comment 给新用户添加备注 -d home_dir 为主目录指定一个名字&#xff08;如果不想用登录名作为主目录名的话&#xff09; -e expire_date 用Y…

Rect 选择感兴趣区域

#include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> // 全局变量源图像 cv::Mat srcImage; // 方法1 利用Rect选择区域(100, 180, 150, 50) void regionExtraction(int xRoi, int yRoi, int widthRoi, int…

paramiko的使用

1 import paramiko2 import sys3 4 5 user "root"6 pwd "123456"7 8 9 10 # 上传文件 11 def sftp_upload_file(server_path, local_path): 12 try: 13 t paramiko.Transport((ip, 22)) 14 t.connect(usernameuser, passwordpwd) …

【C++】多线程与并发【一】

文章目录part 0:多线程简介part 1:多线程构造它用于构造线程对象。参量part 2:多线程析构它破坏线程对象。part 3:多线程operator参量 Parameters返回值Data racespart 4:joinable 它返回线程ive对象是否可连接&#xff0c;则返回true&#xff0c;否则返回false。 表示的是否可…

鼠标按键获取感兴趣区域

#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> #include <stdio.h> using namespace cv; using namespace std; // 全局变量图像源 cv::Mat srcImage; // 所选矩形区域 cv::Rect roiRect; …

git在不同操作系统下自动替换换行符

2019独角兽企业重金招聘Python工程师标准>>> 一天使用docker创建一个镜像执行报一个错 standard_init_linux.go:175: exec user process caused "no such file or directory"参考资料 http://blog.jobbole.com/46200/ http://neue.v2ex.com/t/309469 git …

关于jsp和eclipse服务器端的相关配置和JS的区别

今天配置了一番eclipse的服务器端&#xff0c;由此重新认识了web技术的皮毛&#xff1b; 话不多说&#xff0c;让我们开始&#xff1a; 一&#xff1a; 首先让我们了解一下js和jsp的技术之间的差别&#xff1a; 1&#xff09;js&#xff1a;https://zh.wikipedia.org/wiki/Java…

【C++】多线程与互斥锁【二】

文章目录1. 并发是什么1.1 并发与并行1.2 硬件并发与任务切换1.3 多线程并发与多进程并发2. 为什么使用并发2.1 为什么使用并发2.2 并发和多线程3. 并发需要注意的问题3.1 多线程中的数据竞争实例1&#xff1a;3.2 如何处理数据竞争&#xff1f;实例2&#xff1a;实例3&#xf…

用hosting.json配置ASP.NET Core站点的Hosting环境

通常我们在 Prgram.cs 中使用硬编码的方式配置 ASP.NET Core 站点的 Hosting 环境&#xff0c;最常用的就是 .UseUrls() 。 public class Program {public static void Main(string[] args){var host new WebHostBuilder().UseUrls("http://*:5000").UseKestrel().U…

鼠标按键获取感兴趣区域 2

#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> #include <stdio.h> using namespace cv; using namespace std; // 全局变量图像源 cv::Mat srcImage; // 所选矩形区域 cv::Rect roiRect; …

偷看日历?9款 APP 涉嫌过度获取权限

最近网友已经看累了APP搞事的瓜&#xff0c;3月29日&#xff0c;“9款 APP 涉嫌过度获取权限”又上了热搜。 不久前上海消保委针对网购平台、旅游出行、生活服务等39款手机APP进行了涉及个人信息权限的评测&#xff0c;主要包括四个方面&#xff1a;App所使用的目标API级别、A…

【C++】多线程与条件变量【三】

文章目录1 条件变量是什么&#xff1f;实例1&#xff1a;2 条件变量本质&#xff1f;3 引入条件变量的原因&#xff1f;实例2&#xff1a;实例3&#xff1a;实例4&#xff1a;4 如何使用条件变量&#xff1f;4.1 std::condition_variable实例5&#xff1a;4.2 std::condition_v…

图像遍历反色处理,遍历多通道图片

#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> using namespace cv; // 下标M.at<float>(i,j) 方法1-1 cv::Mat inverseColor1(cv::Mat srcImage) {cv::Mat tempImage srcImage.clone();int row t…

【Treap】bzoj1588-HNOI2002营业额统计

一、题目 Description 营业额统计 Tiger最近被公司升任为营业部经理&#xff0c;他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。 Tiger拿出了公司的账本&#xff0c;账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节…

推荐一款 Flutter Push 推送功能插件

又到了推荐好插件的时候了。开发 APP 避免不了使用「推送」功能。比如&#xff0c;新上架一个商品&#xff0c;或者最新的一条体育新闻&#xff0c;实时推送给用户。 比较了几家推送平台&#xff0c;貌似「极光」出了 Flutter 插件&#xff0c;所以就拿它试试手&#xff0c;顺便…

【C++】多线程与异步编程【四】

文章目录【C】多线程与异步编程【四】0.三问1.什么是异步编程&#xff1f;1.1同步与异步1.2 **阻塞与非阻塞**2、如何使用异步编程2.1 使用全局变量与条件变量传递结果实例1&#xff1a;2.2 使用promise与future传递结果实例2实例32.3使用packaged_task与future传递结果实例42.…

[LintCode] Maximum Subarray 最大子数组

Given an array of integers, find a contiguous subarray which has the largest sum. Notice The subarray should contain at least one number. Have you met this question in a real interview? YesExample Given the array [−2,2,−3,4,−1,2,1,−5,3], the contiguo…

图像补运算:反色处理

cv::Mat inverseColor1(cv::Mat srcImage) {cv::Mat tempImage srcImage.clone();int row tempImage.rows;int col tempImage.cols;// 对各个像素点遍历进行取反for (int i 0; i < row; i){for (int j 0; j < col; j){// 分别对各个通道进行反色处理tempImage.at<…

2018-2019-2 网络对抗技术 20165239Exp3 免杀原理与实践

2018-2019-2 网络对抗技术 20165239 Exp3 免杀原理与实践 win10 ip地址 192.168.18.1 fenix ip地址为 192.168.18.128 &#xff08;1&#xff09;杀软是如何检测出恶意代码的&#xff1f; •根据计算机病毒课程知道了每个病毒都有其对应的特征码&#xff0c;杀软是根据这些特征…

【C++】多线程与原子操作和无锁编程【五】

【C】多线程与原子操作和无锁编程【五】 1、何为原子操作 前面介绍了多线程间是通过互斥锁与条件变量来保证共享数据的同步的&#xff0c;互斥锁主要是针对过程加锁来实现对共享资源的排他性访问。很多时候&#xff0c;对共享资源的访问主要是对某一数据结构的读写操作&#…

jquery中ajax的dataType属性包括哪几项

参考ajax api文档&#xff1a;http://www.w3school.com.cn/jquery/ajax_ajax.asp dataType类型&#xff1a;String预期服务器返回的数据类型。如果不指定&#xff0c;jQuery 将自动根据 HTTP 包 MIME 信息来智能判断&#xff0c;比如 XML MIME 类型就被识别为 XML。在 1.4 中&a…

图像补运算:ptr反色处理

cv::Mat inverseColor3(cv::Mat srcImage) {cv::Mat tempImage srcImage.clone();int row tempImage.rows;// 将3通道转换为单通道int nStep tempImage.cols * tempImage.channels();for(int i 0; i < row; i) {// 取源图像的指针const uchar* pSrcData srcImage.ptr&l…

Android 在运行时请求权限

2019独角兽企业重金招聘Python工程师标准>>> 从 Android 6.0&#xff08;API 级别 23&#xff09;开始&#xff0c;用户开始在应用运行时向其授予权限&#xff0c;而不是在应用安装时授予。此方法可以简化应用安装过程&#xff0c;因为用户在安装或更新应用时不需要…