flip(frame, frame, 1);//支持图像的翻转(上下翻转、左右翻转,以及同时均可)
void flip_test()
{
void cv::flip(
cv::InputArray src, // 输入图像
cv::OutputArray dst, // 输出
int flipCode = 0 // >0: 沿y-轴翻转, 0: 沿x-轴翻转, <0: x、y轴同时翻转
}
getStructuringElement()函数可用于构造一个特定大小和形状的结构元素,用于图像形态学处理。
BackgroundSubtractorMOG2是以高斯混合模型为基础的背景/前景分割算法。它是以2004年和2006年Z.Zivkovic的两篇文章为基础的。这个算法的一个特点是它为每一个像素选择一个合适数目的高斯分布。(上一个方法中我们使用是K高斯分布)。这样就会对由于亮度等发生变化引起的场景变化产生更好的适应。和前面一样我们需要创建一个背景对象。但在这里我们我们可以选择是否检测阴影。如果detectShadows = True(默认值),它就会检测并将影子标记出来,但是这样做会降低处理速度。影子会被标记为灰色
原文链接:https://blog.csdn.net/zhangyonggang886/article/details/51638655
形态学滤波:对二值图像进行开运算与闭运算。
morphologyEx()函数可以实现形态学处理的很多运算,慢慢来~
CV_EXPORTS_W void morphologyEx(InputArray src,//输入图像
OutputArray dst,//输出图像
int op, //标识符,表示形态学运算的类型
InputArray kernel,//结构元素,即用于卷积的内核
Point anchor = Point(-1, -1),//默认值,锚点位于中心
int iterations = 1,//默认值,迭代次数
int borderType = BORDER_CONSTANT,//默认值
const Scalar& borderValue = morphologyDefaultBorderValue());//默认值
1.对二值图像开运算
定义:先腐蚀再膨胀,相当于先用结构元素B对A腐蚀,再对腐蚀结果用同样的结构元进行膨胀操作。
等幂性:对同样的A,做多次开运算的结果与做一次是一样的。
结果:开运算的边界是由这样一些点组成的,就是当B沿A的内部边界滚动时,B中所能达到的A的内部边界的最远的点。
2.对二值图像闭运算
定义:先膨胀再腐蚀,相当于先用结构元B对A进行膨胀,再对膨胀结果用同样的结构元进行腐蚀操作,过程与开运算正好相反。
等幂性:对同样的A,做多次闭运算的结果与做一次是一样的。
就像腐蚀和膨胀的关系一样,开和闭也是关于集合补和反转的对偶。
3.对二值图像开、闭运算的基本作用
从开、闭运算的基本定义和运行过程可以看出,这两种集合操作的所能导致的大致效果如下:
开运算通常对图像轮廓进行平滑,使狭窄的“地峡”形状断开,去掉细的突起。
闭运算也是趋向于平滑图像的轮廓,但于开运算相反,它一般使窄的断开部位和细长的沟熔合,填补轮廓上的间隙。
可以这样想,对一副二值图像进行开运算,结果是对图像白色部分去掉细的突起,相当于对图像黑色部分填补轮廓上的间隙。对一副二值图像进行闭运算,结果是对图像白色部分填补轮廓上的间隙,相当于对图像黑色部分去掉细的突起。二值图像,非黑即白,你把黑白转换一下,更容易明白开闭运算
原文链接:https://blog.csdn.net/misterjiajia/article/details/80320093
cvtColor(src_gray, dst, CV_GRAY2BGR);//灰度转RGB
cvtColor(src_gray, dst, COLOR_BGR2GRAY);//RGB转灰度
//是边缘保留的滤波方法,避免边缘像素信息丢失,保留了图像轮廓不变。可以用于美颜中
//高斯双边滤波 原始 新的 半径的范围 表示像素的差值100以内 不知道
bilateralFilter(zeor_a, new_img,5, 100, 10);
// //此句代码的OpenCV3版为:(转灰度图)
cvtColor(a_img, rgrb_a, COLOR_BGR2GRAY);
//高斯滤波 权重是一个高斯分布 素值仍然较大 保留原有的特点 部分地克服了边缘信息的丢 无法完全避免,因为没有考虑像素值的不同
GaussianBlur(src, dst2, Size(5, 5), 11);
//中值滤波 椒盐噪点 是一种统计排序滤波器,
medianBlur(src, dst, 5); //5为卷积核的大小
//【3】先用使用 3x3内核来降噪(均值滤波)权重都为1 各个区域的像素值比较均匀,无法克服边缘像素信息丢失
blur(a_img, rgrb_a, Size(3, 3));
//轮廓提取
Canny(sre_zao, src_gray, 110, 200);//canny边缘检测算子
//Canny()函数:,输入图像、,输出图像、第三个参数是低阈值、第四个参数是高阈值,第五个参数表示Sobel算子的孔径大小,默认值为3,高低阈值的比值最好在2:1到3:1之间。
//图片的旋转
cv::Size src_sz = src.size();
cv::Size dst_sz(src_sz.width, src_sz.height);
Point center = cv::Point(src.cols / 2, src.rows / 2);//旋转中心
//这是一个防射变换矩阵
Mat rot_mat =getRotationMatrix2D(center , 30.0, 1.0);//旋转位置 旋转角度 图像缩放因子
cv::warpAffine(src, over, rot_mat, dst_sz);//输入图片 输出图片 放射变化矩阵 输出图片的尺寸
//https://blog.csdn.net/duwangthefirst/article/details/79971212
Canny(edge, edge, 3, 9, 3);
////【1】创建与src同类型和大小的矩阵(dst)
dstImage.create(srcImage.size(), srcImage.type());
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));//内核的形状(三种形式) 内核的尺寸(轮廓的粗细) 锚点的位置
/*矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE;*/
Mat dst;
erode(src, dst, element);//原始图片 腐蚀后的图 进行腐蚀操作的Mat
//进行二值化
threshold(sre_zao, er_src, 105, 210, CV_THRESH_BINARY);
//adaptiveThreshold(sre_zao, er_src, 230, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 110, 0);
//er_src = 110 < 100 ? (src < 150) : (src > 150);
//vector<Vec2f> lines;
HoughLines(src_gray, lines, 1, CV_PI / 180, 300, 0, 0);
//第二种方法(概率霍夫变换)
vector<Vec4f> plines;
HoughLinesP(src_gray, plines, 1, CV_PI / 180.0, 300, 0, 10);
//基于源图像的方法1 log对数增强
Mat logTransform1001(Mat srcImage, int c)
{
//判断是否是图片
if (srcImage.empty())
cout << "No data" << endl;
Mat resultImage = Mat::zeros(srcImage.size(), srcImage.type());
add(srcImage, Scalar(1.0), srcImage); //计算 r+1
srcImage.convertTo(srcImage, CV_32F); // 转化为32位浮点型
log(srcImage, resultImage); //计算log(1+r)
resultImage = c * resultImage;
//归一化处理
normalize(resultImage, resultImage, 0, 255, NORM_MINMAX);
convertScaleAbs(resultImage, resultImage);
return resultImage;
//基于源图像的方法1 log对数增强(多通道)
Mat logTransform1002(Mat image, int c)
{
Mat imageLog(image.size(), CV_32FC3);
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++)
{
imageLog.at<Vec3f>(i, j)[0] =c * log(1 + image.at<Vec3b>(i, j)[0]);
imageLog.at<Vec3f>(i, j)[1] =c * log(1 + image.at<Vec3b>(i, j)[1]);
imageLog.at<Vec3f>(i, j)[2] =c * log(1 + image.at<Vec3b>(i, j)[2]);
}
}
//归一化到0~255
normalize(imageLog, imageLog, 0, 255, CV_MINMAX);
//转换成8bit图像显示
convertScaleAbs(imageLog, imageLog);
return imageLog;
}
//幂函数增强
Mat dst(src.size(), CV_32FC3);
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
for (int m = 0; m < 3; m++)
{
dst.at<Vec3f>(i, j)[m] = (src.at<Vec3b>(i, j)[m])^(1);
}
//dst.at<uchar>(i, j) = (src.at<uchar>(i, j) ^ (1 / 10);
}
}
//////归一化到0~255
//normalize(dst,dst, 0, 255, CV_MINMAX);
normalize(dst, dst, 0, 255,CV_MINMAX);
//////转换成8bit图像显示
convertScaleAbs(dst, dst);
}
int c = 2;
Mat dst(src.size(), CV_32FC3);
//Mat dst(src);
for (int i = 0; i < src.rows; i++)
{
for (int k = 0; k < src.cols; k++)
{
for (int j = 0; j < 3; j++)
{
dst.at<Vec3f>(i, k)[j] =c * log(1 + src.at<Vec3b>(i,k)[j] );//防止以零为低数
}
}
}
////归一化到0~255
normalize(dst,dst, 0, 255, CV_MINMAX);
////转换成8bit图像显示
convertScaleAbs(dst, dst);
//【1】读入视频
VideoCapture capture("1.avi");
//【2】循环显示每一帧
while(1)
{
Mat frame;//定义一个Mat变量,用于存储每一帧的图像
capture>>frame; //读取当前帧
imshow("读取视频",frame); //显示当前帧
waitKey(30); //延时30ms
}
return 0;
namedWindow(window_name, CV_WINDOW_AUTOSIZE);
//这个名字与imshow()里面的名字是一个的,
createTrackbar("element size", window_name, &element_size, max_size, callback_demo); //利用回调函数创建滑动按钮示例
//滑动框的名字 滑动框在那个父的窗口实现 开始 结束 会掉
callback_demo(0, 0);//在这里回调函数,参数好像固定
void callback_demo_erode(int, void*) {}
//概率霍夫变换
void houghp() {
cv::Mat image = cv::imread("road.png");
cv::Mat midImage;
cv::Canny(image, midImage, 50, 200, 3);
std::vector<cv::Vec4i> lines;
cv::HoughLinesP(midImage, lines, 1, CV_PI / 180, 50); // 输入的时二值图像,输出vector向量
for (int i=0; i < lines.size(); i++) {
cv::Point pt1(lines[i][0], lines[i][1]);
cv::Point pt2(lines[i][2], lines[i][3]);
cv::line(image, pt1, pt2, cv::Scalar(0, 255, 255));
}
cv::imshow("概率霍夫变换", image);
}
//分通道显示
vector<Mat> bgr_planes;
split(src, bgr_planes);
//imshow("b", bgr_planes[0]);
//imshow("g", bgr_planes[0]);
//imshow("r", bgr_planes[0]);
//设定像素取值范围
int histSize = 256;
float range[] = { 0,256 };
const float *histRanges = { range };
//三个通道分别计算直方图
Mat b_hist, g_hist, r_hist;
calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);
calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);
calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);
/*onst Mat* images:输入图像
int nimages:输入图像的个数
const int* channels:需要统计直方图的第几通道
InputArray mask:掩膜,,计算掩膜内的直方图 ...Mat()
OutputArray hist:输出的直方图数组
int dims:需要统计直方图通道的个数
const int* histSize:指的是直方图分成多少个区间,就是 bin的个数
const float** ranges: 统计像素值得区间
bool uniform = true::是否对得到的直方图数组进行归一化处理
bool accumulate = false:在多个图像时,是否累计计算像素值得个数*/
//创建直方图画布并归一化处理
int hist_h = src.rows;
int hist_w = src.cols;
int bin_w = hist_w / histSize;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
//render histogram chart 在直方图画布上画出直方图
for (int i = 1; i < histSize; i++)
{
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA);
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA);
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA);
}
imshow("直方图", histImage);
头文件:#include<cmath>
int x, n;
n = (int)sqrt((double)x);
sqrt()函数,里面的形参是double型的,所以调用的时候,要强制转换成double型。
sqrt()函数都最后返回值是double型,而n是int型,所以要强制转换n = (int)sqrt((double)x);
视频
//读取视频
VideoCapture capture(“1.avi”);
if (!capture.isOpened())
{
return 0;
}
long totalFrameNumber=capture.get(CV_CAP_PROP_FRAME_COUNT);//获取视频的总帧数
cout << "整个视频共" << totalFrameNumber << "帧" << endl;
//设置开始帧
long frameToStart = 300;
capture.set(CV_CAP_PROP_POS_FRAMES, frameToStart);
cout << "从第" << frameToStart << "帧开始读" << endl;
//设置结束帧
int frameToStop = 400;
if (frameToStop < frameToStart)
{
cout << "结束帧小于开始帧,程序错误,即将退出!" << endl;
return -1;
}
else
{
cout << "结束帧为:第" << frameToStop << "帧" << endl;
}
//获取帧率
double rate = capture.get(CV_CAP_PROP_FPS);
cout << "帧率为:" << rate << endl;
//角度与弧度
1弧度 = pai / 180 度
1度 = 180 / pai *弧度
也就是说灰度图不一定是单通道,但是单通道一定是灰度图!
色调、饱和度、亮度(Hue, Saturation, Value)
色调(偏向):
色调决定一个像素点中的颜色更偏向于哪一方(RGB):
饱和度(深浅):
饱和度决定了颜色空间中颜色分量,饱和度越高,说明颜色越深,饱和度越低,说明颜色越浅
亮度(明暗):
亮度决定颜色空间中颜色的明暗程度!
RGB和HSV关系:
其实色调,饱和度,亮度都是通过特定的算法经过计算修改RGB三色而达到的控制颜色效果!
色调(H:hue):用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
饱和度(S:saturation):取值范围为0.0~1.0,值越大,颜色越饱和。
亮度(V:value):取值范围为0(黑色)~255(白色)。