声明:
1、本文是部分代码,直接复制不可运行。
2、函数各项参数意义未详细说明。
3、
报错一般情况有:
图片的文件路径是 “/” (与电脑上复制的路径“\”不同)
使用的Mat类为空白数据、
函数使用的Mat类与函数要求不匹配(有些函数只处理灰度图或二值化图)、
ROI截图时坐标数据超出该图片的范围时、
基础部分:
Mat类:可用于存放图片数据。
waitKey(0); //暂停 按键有按下在继续运行
waitKey(10); //暂停 10毫秒
读取图片、设置窗口、展示图片、保存图片、程序暂停
Mat img; //存图
img = imread("i1.png",IMREAD_COLOR); //IMREAD_COLOR :彩色图像
Mat gray = imread("i1.png", IMREAD_GRAYSCALE); // :灰度化
namedWindow("img", WINDOW_AUTOSIZE); //自适应窗口大小
namedWindow("gray", WINDOW_NORMAL); //正常
cout << "width:" << img.size().width << endl;
cout << "height:" << img.size().height << endl;
cout << "channels:" << img.channels()<< endl;
imshow("img", img);
imshow("gray", gray);
imwrite("i11.jpg", gray);
waitKey(0);
图片格式转换:
转HSV、灰度格式
Mat img32;
img.convertTo(img32,CV_32F,1/255.0,0);
Mat HSV, HSV32;
cvtColor(img,HSV,COLOR_BGR2HSV);
cvtColor(img32,HSV32,COLOR_BGR2HSV);
Mat gray0, gray1;
cvtColor(img, gray0, COLOR_BGR2GRAY);
cvtColor(img, gray1, COLOR_RGB2GRAY);
通道分离、通道合并
Mat imgs[3];
split(img, imgs);
Mat img0, img1, img2;
img0 = imgs[0];
img1 = imgs[1];
img2 = imgs[2];
Mat img_H;
merge(imgs,3,img_H);
图像二值化:
//灰度图像大律法和三角形法二值化
Mat img = imread("E:/Download/OpenCV/i1.png",IMREAD_GRAYSCALE);
Mat imgt1, imgtt;
threshold(img, imgt1, 20, 240, THRESH_BINARY | THRESH_OTSU);
threshold(img, imgtt, 50, 250, THRESH_BINARY | THRESH_TRIANGLE);
imshow("imgt1", imgt1);
imshow("imgtt", imgtt);
waitKey(0);
//自适应二值化
Mat adaptive_mean, adaptive_gauss;
adaptiveThreshold(img, adaptive_mean,250,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,51,0); //平均值
adaptiveThreshold(img, adaptive_gauss, 250, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 49, 0); //加权和
imshow("adaptive_mean",adaptive_mean);
imshow("adaptive_gauss", adaptive_gauss);
图像大小,角度,旋转等操作:
Mat gray = imread("E:/Download/OpenCV/i1.png",IMREAD_GRAYSCALE);
Mat smallImg, bigImg0, bigImg1, bigImg2;
resize(gray, smallImg, Size(15, 15), 0, 0, INTER_AREA); //图像缩小
resize(smallImg, bigImg0,Size(30, 30), 0, 0, INTER_NEAREST); //最近邻差值
resize(smallImg, bigImg1, Size(30, 30), 0, 0, INTER_LINEAR); //双线性差值
resize(smallImg, bigImg2, Size(30, 30), 0, 0, INTER_CUBIC); //双三次差值
Mat img_x, img_y, img_xy;
flip(gray, img_x, 0); //x轴对称
flip(gray, img_y, 1); //y轴对称
flip(gray, img_xy, -1); //先x轴对称,再y轴对称(倒)
imshow("smallImg", smallImg);
imshow("bigImg0", bigImg0);
imshow("bigImg1", bigImg1);
imshow("bigImg2", bigImg2);
// 图像连接
Mat img, img0, img1;
hconcat(bigImg2, bigImg0, img0);
hconcat(bigImg0, bigImg1, img1); //横向连接
vconcat(img0, img1, img); //竖向连接
imshow("img0", img0);
imshow("img1", img1);
imshow("img", img);
waitKey(0);
绘制直线,圆,矩形等:
Mat img = Mat::zeros(Size(512, 512), CV_8UC3); //生成一个黑色图像用于绘制几何图形
circle(img, Point(50, 50), 25, Scalar(255, 255, 255), -1); //绘制一个实心圆
circle(img, Point(100, 50), 20, Scalar(255, 255, 255),4); //绘制一个空心圆
line(img, Point(100, 100), Point(200, 100), Scalar(255, 255, 255), 2,LINE_4,0); //一条直线
ellipse(img, Point(300, 255), Size(100, 70), 0,0,100,Scalar(255, 255, 255), -1);//实心椭圆的一部分
rectangle(img, Point(50, 400), Point(100, 450), Scalar(125, 125, 125), -1); //矩形
// 绘制多边形
Point pp[2][6];
pp[0][0] = Point(72, 200);
pp[0][1] = Point(142, 204);
pp[0][2] = Point(226, 263);
pp[0][3] = Point(172, 310);
pp[0][4] = Point(117, 319);
pp[0][5] = Point(15, 260);
pp[1][0] = Point(359, 339);
pp[1][1] = Point(447, 351);
pp[1][2] = Point(504, 349);
pp[1][3] = Point(484, 433);
pp[1][4] = Point(418, 449);
pp[1][5] = Point(354, 402);
Point pp2[5];
pp2[0] = Point(350, 83);
pp2[1] = Point(463, 90);
pp2[2] = Point(500, 171);
pp2[3] = Point(421, 194);
pp2[4] = Point(338, 141);
const Point* pts[3] = { pp[0],pp[1],pp[2] }; //pts变量的生成
int npts[] = { 6,6,5 }; // 顶点个数数组的生成
fillPoly(img, pts, npts, 3, Scalar(125, 125, 125), 8); //绘制三个多边形
putText(img,"opencv_4.", Point(100,400),2,1,Scalar(255,255,255));//生成文字
imshow("img", img);
waitKey(0);
ROI截图自己需要的区域:
Mat img = imread("E:/Download/OpenCV/i1.png");
Mat noobcv = imread("E:/Download/OpenCV/i11.jpg");
Mat ROI1, ROI2, ROI2_copy, mask, img2, img_copy;
resize(noobcv, mask, Size(200, 200));
img2 = img; //浅拷贝
//深拷贝的两种方式
img.copyTo(img_copy);
//两种在图中截取ROI 区域的方式
Rect rect(206, 206, 200, 200); //定义ROI 区域
ROI1 = img(rect); //截图
ROI2 = img(Range(300, 500), Range(300, 500)); //第二种截图方式
img(Range(300, 500), Range(300, 500)).copyTo(ROI2_copy); //深拷贝
mask.copyTo(ROI1); //在图像中加入部分图像
imshow("加入后:", img);
imshow("深拷贝img_copy:", img_copy);
imshow("ROI对ROI2的影响:", ROI2);
imshow("深拷贝ROI2_copy:", ROI2_copy);
circle(img, Point(300, 300), 20, Scalar(0, 0, 255), -1); //绘制一个实心圆
imshow("浅拷贝:", img2);
imshow("画圆对ROI1的影响:", ROI1);
Mat img1 = imread("E:/Download/OpenCV/big.jpg");
//Mat center_img = img1(Range(750, 560), Range(870, 680));
Mat ROI12;
Rect rect1(750, 560, 120, 120); //定义ROI 区域
ROI12 = img1(rect1); //截图
imshow("ROI12:", ROI12);
waitKey(0);
滑动条:
Mat img = Mat::zeros(300, 512, CV_8UC3);
namedWindow("img");
createTrackbar("B", "img", 0, 255, callBack); //当前窗口创建滑动条
createTrackbar("G", "img", 0, 255, callBack);
createTrackbar("R", "img", 0, 255, callBack);
createTrackbar("0:off\n1:on", "img", 0, 1, callBack);
while (true)
{
imshow("img", img);
if (waitKey(1) == 27)
break;
int b = getTrackbarPos("B", "img"); //获取当前滑动条位置的对应值
int g = getTrackbarPos("G", "img");
int r = getTrackbarPos("R", "img");
int s = getTrackbarPos("0:off\n1:on", "img");
if (s == 0)
img = Scalar(0, 0, 0);
else
img = Scalar(b, g, r);
}
waitKey(0);
鼠标相应事件:
Mat img, imgPoint; //全局图像
Point prePoint; //前一时刻鼠标的坐标,用于绘制直线
void mouse(int event, int x, int y, int flags, void*);
int main()
{
img = imread("E:/Download/OpenCV/i1.png");
img.copyTo(imgPoint);
imshow("img1", img);
imshow("img2", imgPoint);
setMouseCallback("img1",mouse,0); //鼠标影响
waitKey(0);
return 0;
}
void mouse(int event, int x,int y,int flags,void*)
{
if (event == EVENT_MBUTTONDOWN) //单击右键
{
cout << "点击鼠标左键才可以绘制轨迹" << endl;
}
if (event == EVENT_LBUTTONDOWN) //单击左键,输出坐标
{
prePoint = Point(x, y);
cout << "轨迹起始坐标" << prePoint << endl;
}
if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON)) //鼠标按住左键移动图像
{
//通过绘制直线显示鼠标移动轨迹
Point pt(x, y);
line(img, prePoint, pt, Scalar(255, 255, 255), 2, 5, 0);
prePoint = pt;
imshow("img1", img);
//通过改变图像像素显示鼠标移动轨迹
imgPoint.at<Vec3b>(y, x) = Vec3b(255, 255, 255);
imgPoint.at<Vec3b>(y, x-1) = Vec3b(255, 255, 255);
imgPoint.at<Vec3b>(y, x+1) = Vec3b(255, 255, 255);
imgPoint.at<Vec3b>(y+1, x) = Vec3b(255, 255, 255);
imgPoint.at<Vec3b>(y+1, x) = Vec3b(255, 255, 255);
imshow("img2", imgPoint);
}
}
鼠标截取感兴趣区域的功能函数:
Point sp(-1,-1);
Point ep(-1, -1);
Mat temp;
static void on_draw(int event, int x, int y, int flags, void* userdata) {
Mat image = *((Mat*)userdata);
if (event == EVENT_LBUTTONDOWN) { //左键按下
sp.x = x;
sp.y = y;
cout << "start point " << sp << endl;
}
else if (event == EVENT_LBUTTONUP) { //左键松开
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy >0) {
Rect box(sp.x, sp.y,dx,dy);
temp.copyTo(image);
imshow("ROI区域",image(box)); //鼠标选择的区域
rectangle(image, box,Scalar(255,0,0),2,8,0);
imshow("鼠标绘制", image);
sp.x = -1; //绘制完成,清零
sp.y = -1;
}
cout << "start point " << ep << endl;
}
else if(event == EVENT_MOUSEMOVE) { //鼠标移动中
if (sp.x > 0 && sp.y > 0) {
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0) {
Rect box(sp.x, sp.y, dx, dy);
temp.copyTo(image);
rectangle(image, box, Scalar(255, 0, 0), 2, 8, 0);
imshow("鼠标绘制", image);
}
}
}
}
void mouse_drawing_Demo(Mat &image){
namedWindow("鼠标绘制",WINDOW_AUTOSIZE);
setMouseCallback("鼠标绘制", on_draw,(void *)(&image));
imshow("鼠标绘制", image);
temp = image.clone();
}
直方图均衡化:
void drawHist(Mat &hist, int type, string name) //归一化并绘制直方图函数
{
int hist_w = 512;
int hist_h = 400;
int width = 2;
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
normalize(hist, hist, 1, 0, type, -1, Mat());
for (int i = 1; i <= hist.rows; i++)
{
rectangle(histImage, Point(width*(i - 1), hist_h - 1),
Point(width*i - 1, hist_h - cvRound(hist_h*hist.at<float>(i - 1)) - 1),
Scalar(255, 255, 255), -1);
}
imshow(name, histImage);
}
int main()
{
Mat img = imread("E:/Download/OpenCV/i1.png");
Mat gray, hist, hist2;
cvtColor(img, gray, COLOR_BGR2GRAY);
Mat equalImg;
equalizeHist(gray, equalImg); //将图像直方图均衡化
const int channels[1] = { 0 };
float inRanges[2] = { 0,255 };
const float* ranges[1] = { inRanges };
const int bins[1] = { 256 };
calcHist(&gray, 1, channels, Mat(), hist, 1, bins, ranges);
calcHist(&equalImg, 1, channels, Mat(), hist2, 1, bins, ranges);
drawHist(hist, NORM_INF, "hist");
drawHist(hist2, NORM_INF, "hist2");
imshow("gray", gray);
imshow("均衡化equalImg", equalImg);
waitKey(0);
return 0;
}
边缘检测:
Mat img = imread("E:/Download/OpenCV/i1.png",IMREAD_ANYCOLOR);
Mat resultX, resultY, resultXY;
Sobel(img, resultX, CV_16S, 1, 0, 1); //X方向一阶边缘
convertScaleAbs(resultX, resultX); //求取绝对值
Sobel(img, resultY, CV_16S, 0, 1, 1); //Y方向一阶边缘
convertScaleAbs(resultY, resultY);
resultXY = resultX + resultY; //整图的一阶边缘
imshow("resultX", resultX);
imshow("resultY", resultY);
imshow("resultXY", resultXY);
cout << "接下来进行Scharr边缘的检测" << endl;
waitKey(0);
Scharr(img, resultX, CV_16S, 1, 0); //X方向一阶边缘
convertScaleAbs(resultX, resultX);
Scharr(img, resultY, CV_16S, 0, 1); //Y方向一阶边缘
convertScaleAbs(resultY, resultY);
resultXY = resultX + resultY; //整图的一阶边缘
imshow("resultX", resultX);
imshow("resultY", resultY);
imshow("resultXY", resultXY);
cout << "接下来生成边缘检测器" << endl;
waitKey(0);
Mat soble_xl, soble_yl; //存放分离Sobel算子
Mat scharr_x, scharr_y; //存放分离Scharr算子
Mat sobleX1, scharrX; //存放最终算子
getDerivKernels(soble_xl, soble_yl, 1, 0, 3); //Sobel算子生成
soble_xl = soble_xl.reshape(CV_8U, 1);
sobleX1 = soble_yl * soble_xl; //计算滤波器
getDerivKernels(scharr_x, scharr_y,1,0,FILTER_SCHARR); //Scharr算子生成
scharr_x = scharr_x.reshape(CV_8U, 1);
scharrX = scharr_y * scharr_x; //计算滤波器
cout << "X方向一阶Sobel算子" << endl << sobleX1 <<endl;
cout << "X方向一阶Scharr算子" << endl << scharrX << endl;
waitKey(0);
Mat canimg,gray;
// cvtColor(img, gray, COLOR_BGR2GRAY);
Canny(img, canimg, 200, 80, 3);
imshow("canimg", canimg);
//imshow("gray", gray);
waitKey(0);
轮廓外接多边形:
Mat img = imread("E:/Download/OpenCV/i1.png"); //取图,
Mat img1, img2;
img.copyTo(img1); //深拷贝用来绘制最大外接矩形
img.copyTo(img2); //深拷贝用来绘制最小外接矩形
imshow("img", img);
//去噪声与二值化
Mat canny;
Canny(img, canny, 0, 250, 3, false);
imshow("canny", canny);
//膨胀运算,将细小缝隙填补上
Mat kernel = getStructuringElement(0, Size(3, 3));
dilate(canny, canny, kernel);
//轮廓发现与绘制
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(canny, contours, hierarchy, 0, 2, Point());
//寻找轮廓的外接矩形
for (int n = 0; n < contours.size(); n++)
{
Rect rect = boundingRect(contours[n]); //最大外接矩形
rectangle(img, rect, Scalar(0, 0, 255), 2, 8, 0);
RotatedRect rrect = minAreaRect(contours[n]); //最小外接矩形
Point2f points[4];
rrect.points(points); //读取最小外接矩形的四个顶点
Point2f cpt = rrect.center; //最小外接矩形的中心
//绘制旋转矩形与中心位置
for (int i = 0; i < 4; i++)
{
if (i == 3)
{
line(img2, points[i], points[0], Scalar(0, 255, 0), 2, 8, 0);
break;
}
line(img2, points[i], points[i+1], Scalar(0, 255, 0), 2, 8, 0);
}
//绘制矩形中心
circle(img2, cpt, 4, Scalar(255, 0, 0), -1, 8, 0);
}
imshow("max", img1);
imshow("min", img2);
waitKey(0);
直线检测:
Mat img = imread("E:/Download/OpenCV/i1.png", IMREAD_GRAYSCALE); //取图,
Mat edge;
Canny(img, edge, 80, 180, 3, false); //检测边缘图像,并二值化
//利用渐近概率式霍夫变换提取直线
vector<Vec4i> linesP1, linesP2;
HoughLinesP(edge, linesP1, 1, CV_PI / 180, 2, 30, 3); //两点连接最大距离10
HoughLinesP(edge, linesP2, 1, CV_PI / 180, 6, 30, 8); //两点连接最大距离30
//在原图像中绘制最大距离10的直线
Mat img1;
img.copyTo(img1); //深拷贝
for (size_t i = 0; i < linesP1.size(); i++)
{
line(img1, Point(linesP1[i][0], linesP1[i][1]), Point(linesP1[i][2], linesP1[i][3]), Scalar(255), 3);
}
//在原图像中绘制最大距离30的直线
Mat img2;
img.copyTo(img2); //深拷贝
for (size_t i = 0; i < linesP2.size(); i++)
{
line(img2, Point(linesP2[i][0], linesP2[i][1]), Point(linesP2[i][2], linesP2[i][3]), Scalar(255), 3);
}
imshow("img", img);
waitKey(0);
imshow("edge", edge);
waitKey(0);
imshow("img1", img1);
waitKey(0);
imshow("img2", img2);
waitKey(0);
模板匹配:
Mat img = imread("E:/Download/OpenCV/i1.png");
Mat temp= imread("E:/Download/OpenCV/edge1.png"); //模板
Mat result;
matchTemplate(img, temp, result, TM_CCOEFF_NORMED); //匹配
double maxVal, minVal; //maxVal 左上角,
Point maxLoc, minLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc); //最大最小的位置
rectangle(img, Point(maxLoc.x, maxLoc.y), Point(maxLoc.x + temp.cols, maxLoc.y + temp.rows), Scalar(0, 0, 255), 2);
line(img, Point(maxLoc.x + temp.cols, maxLoc.y), Point(maxLoc.x, maxLoc.y + temp.rows), Scalar(255, 255, 255), 2, LINE_4, 0); //一条直线
imshow("img", img);
imshow("temp", temp);
imshow("result", result);
waitKey(0);
中值滤波:
Mat img = imread("E:/Download/OpenCV/i1.png",IMREAD_ANYCOLOR);
Mat imgResult1, imgResult2;
medianBlur(img, imgResult1, 3);
medianBlur(img, imgResult2, 9);
imshow("imgResult1", imgResult1);
imshow("imgResult2", imgResult2);
图像分割水漫填充法:
system("color F0");
Mat img = imread("E:/Download/OpenCV/i1.png");
RNG rng(10086); //随机树,用于随机生成像素
int connecetivity = 4; //连通邻域方式
int maskVal = 255; //掩码图像的数值
int flags = connecetivity | (maskVal << 8)|FLOODFILL_FIXED_RANGE; //漫水填充操作方式标志
//设置与选中像素点的差值
Scalar loDiff = Scalar(20, 20, 20);
Scalar upDiff = Scalar(20, 20, 20);
//声明掩模矩阵变量
Mat mask = Mat::zeros(img.rows + 2, img.cols + 2, CV_8UC1);
while (true)
{
//随机产生图像中某一像素点
int py = rng.uniform(0, img.rows - 1);
int px = rng.uniform(0, img.cols - 1);
Point point = Point(px,py);
//彩色图像中填充的像素值
Scalar newVal = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
//漫水填充函数
int area = floodFill(img, mask, point, newVal, &Rect(), loDiff, upDiff, flags);
//输出像素点和填充的像素数目
cout << "像素点x:" << point.x << " y:" << point.y <<" 填充像素数目:"<< area << endl;
//输出结果
imshow("填充的彩色图像", img);
imshow("掩模图像", mask);
//判断是否结束程序
int c=waitKey(0);
if ((c & 255) == 27)
{
break;
}
}
卷积过滤:
Mat image = imread("E:/Download/OpenCV/i1.png");
// Print Error message if image is null
if (image.empty())
{
cout << "Could not read image" << endl;
}
// Apply identity filter using kernel
Mat kernel1 = (Mat_<double>(3, 3) << 0, 0, 0, 0, 1, 0, 0, 0, 0);
Mat identity;
filter2D(image, identity, -1, kernel1, Point(-1, -1), 0, 4);
imshow("Original", image);
imshow("Identity", identity);
waitKey();
imwrite("identity.jpg", identity);
destroyAllWindows();
// Blurred using kernel
// Initialize matrix with all ones
Mat kernel2 = Mat::ones(5, 5, CV_64F);
// Normalize the elements
kernel2 = kernel2 / 25;
Mat img;
filter2D(image, img, -1, kernel2, Point(-1, -1), 0, 4);
imshow("Original", image);
imshow("Kernel blur", img);
imwrite("blur_kernel.jpg", img);
waitKey();
destroyAllWindows();
waitKey(0);
腐蚀
Mat image = imread("E:/Download/OpenCV/i1.png");
if (image.empty())
{
cout << "Could not read image" << endl;
}
Mat erodeSrc1, erodeSrc2,struct2, struct1;
struct1 = getStructuringElement(0, Size(5, 5)); //矩形结构元素
struct2 = getStructuringElement(1, Size(5, 5)); //十字结构元素
erode(image, erodeSrc1, struct1);
erode(image, erodeSrc2, struct2);
imshow("image", image);
imshow("erodeSrc1", erodeSrc1);
imshow("erodeSrc2", erodeSrc2);
waitKey(0);
打开视频:
VideoCapture video;
video.open("E:/Download/OpenCV/04 videoload/Left.mp4");
if (!video.isOpened())
{
cout << "视频错误" << endl;
return -1;
}
cout << "视频帧率" << video.get(CAP_PROP_FPS) << endl;
cout << "视频宽度" << video.get(CAP_PROP_FRAME_WIDTH) << endl;
cout << "视频高度" << video.get(CAP_PROP_FRAME_HEIGHT) << endl;
while (true)
{
Mat frame;
video >> frame; //获取一帧
if (frame.empty())
{
break;
}
imshow("video", frame);
uchar c = waitKey(1000/ video.get(CAP_PROP_FPS)); //视频原速播放
if (c == 'q')
{
imwrite("big.jpg", frame);
break;
}
}
图片亮度的加减乘除:
Mat operators;
Mat img_3 = Mat::zeros(image.size(), image.type()); //创建一个与image图片同像素宽高、同类型的空白Mat类
img_3 = Scalar(10,10, 10);
multiply(image, img_3, operators); imshow("ope:*", operators); //被乘、乘数、结果
add(image, img_3, operators); imshow("ope:+", operators);
subtract(image, img_3, operators); imshow("ope:-", operators);
divide(image, img_3, operators); imshow("ope:/", operators);
键盘反馈:
Mat key_dst;
while (true) {
int c = waitKey(100);
if (c == 27) { //Esc
break;
}
else if (c == 49) { // 1
break;
}
else if (c == 50) { // 2
break;
}
else if (c == 51) { // 3
break;
}
cout << c << endl;
}
Mat的 与、或、非、异或操作:
Mat m1=Mat::zeros(Size(256,256),CV_8UC3);
Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
rectangle(m1, Rect(100,100,80,80),Scalar(255,255,0),-1,LINE_8,0);
rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
Mat bit_dst;
bitwise_and(m1,m2, bit_dst);
imshow("bit_dst and", bit_dst);
bitwise_or(m1, m2, bit_dst);
imshow("bit_dst or", bit_dst);
bitwise_not(m1, bit_dst);
imshow("bit_dst not", bit_dst);
bitwise_xor(m1, m2, bit_dst);
imshow("bit_dst xor", bit_dst);
双边模糊:
Mat dst;
bilateralFilter(image,dst,0,100,10);
imshow("双边模糊", dst);