中间隔了好长时间没写啊,这段也没怎么用。
本节主要介绍OpenCV的imgproc模块的图像处理部分:
1. 线性滤波:均值滤波与高斯滤波
2. 非线性滤波:中值滤波、双边滤波
3. 图像形态学:腐蚀与膨胀,开运算、闭运算,形态学梯度,顶帽、黑帽
4. 漫水填充
5. 图像金字塔及图片尺寸缩放
6. 阈值化
本章示例较多,示例列表:
1.图像滤波
2.腐蚀与膨胀
3.漫水填充
4.图像金字塔
5.基本阈值操作
源码:
#include
#include
using namespace std;
using namespace cv;
Mat g_srcImage, g_dstImage1, g_dstImage2, g_dstImage3, g_dstImage4, g_dstImage5;
int g_nBoxFilterValue = 6; //方框滤波内核值
int g_nMeanBlurValue = 10; //均值滤波内核值
int g_nGaussianBlurValue = 6; //高斯滤波内核值
int g_nMedianBlurValue = 10; //中值滤波内核值
int g_nBilateralFilterValue = 10; //双边滤波内核值
static void on_BoxFilter(int, void *); //方框滤波
static void on_MeanBlur(int, void *); //均值滤波
static void on_GaussianBlur(int, void *); //高斯滤波
static void on_MedianBlur(int, void *); //中值滤波
static void on_BilateralFilter(int, void *); //双边滤波
int main()
{
g_srcImage = imread("poster_girl_2.jpg");
g_dstImage1 = g_srcImage.clone();
g_dstImage2 = g_srcImage.clone();
g_dstImage3 = g_srcImage.clone();
g_dstImage4 = g_srcImage.clone();
g_dstImage5 = g_srcImage.clone();
namedWindow("【原图窗口】");
imshow("【原图窗口】", g_srcImage);
//方框滤波
namedWindow("【方框滤波】");
createTrackbar("内核值:", "【方框滤波】", &g_nBoxFilterValue, 50, on_BoxFilter);
on_BoxFilter(g_nBoxFilterValue, 0);
//均值滤波
namedWindow("【均值滤波】");
createTrackbar("内核值:", "【均值滤波】", &g_nMeanBlurValue, 50, on_MeanBlur);
on_MeanBlur(g_nMeanBlurValue, 0);
//高斯滤波
namedWindow("【高斯滤波】");
createTrackbar("内核值:", "【高斯滤波】", &g_nGaussianBlurValue, 50, on_GaussianBlur);
on_GaussianBlur(g_nGaussianBlurValue, 0);
//中值滤波
namedWindow("【中值滤波】");
createTrackbar("内核值:", "【中值滤波】", &g_nMedianBlurValue, 50, on_MedianBlur);
on_MedianBlur(g_nMedianBlurValue, 0);
//双边滤波
namedWindow("【双边滤波】");
createTrackbar("内核值:", "【双边滤波】", &g_nBilateralFilterValue, 50, on_BilateralFilter);
on_BilateralFilter(g_nBilateralFilterValue, 0);
cout << "运行成功,请调整滚动条观察图像效果" << endl << "按下'q'键时,程序退出";
while (char(waitKey(1)) != 'q');
return 0;
}
static void on_BoxFilter(int, void *)
{
boxFilter(g_srcImage, g_dstImage1, -1, Size(g_nBoxFilterValue+1, g_nBoxFilterValue+1));
imshow("【方框滤波】", g_dstImage1);
}
static void on_MeanBlur(int, void *)
{
blur(g_srcImage, g_dstImage2, Size(g_nMeanBlurValue + 1, g_nMeanBlurValue + 1));
imshow("【均值滤波】", g_dstImage2);
}
static void on_GaussianBlur(int, void *)
{
GaussianBlur(g_srcImage, g_dstImage3, Size(g_nGaussianBlurValue*2 + 1, g_nGaussianBlurValue*2 + 1), 0);
imshow("【高斯滤波】", g_dstImage3);
}
static void on_MedianBlur(int, void *)
{
medianBlur(g_srcImage, g_dstImage4, g_nMedianBlurValue*2 + 1);
imshow("【中值滤波】", g_dstImage4);
}
static void on_BilateralFilter(int, void *)
{
bilateralFilter(g_srcImage, g_dstImage5, g_nBilateralFilterValue, g_nBilateralFilterValue*2, g_nBilateralFilterValue / 2);
imshow("【双边滤波】", g_dstImage5);
}
源码:
#include
#include
using namespace std;
using namespace cv;
Mat g_srcImage, g_dstImage;
int g_erodeOrDilate = 0; //0表示腐蚀erode,1表示膨胀dilate
int g_nStructElementSize = 3;
void Process(); //腐蚀和膨胀的处理函数
void on_TrackbarNumChange(int, void*);
void on_ElementSizeChange(int, void*);
int main()
{
g_srcImage = imread("poster_cat_1.jpg");
namedWindow("【原始图】");
imshow("【原始图】", g_srcImage);
namedWindow("【效果图】");
//获取自定义核
Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1, 2 * g_nStructElementSize + 1));
erode(g_srcImage, g_dstImage, element);
imshow("【效果图】", g_dstImage);
//创建轨迹条
createTrackbar("腐蚀/膨胀", "【效果图】", &g_erodeOrDilate, 1, on_TrackbarNumChange);
createTrackbar("内核尺寸", "【效果图】", &g_nStructElementSize, 21, on_ElementSizeChange);
cout << "运行成功,请调整滚动条观察图像效果" << endl << "按下'q'键时,程序退出";
while (char(waitKey(1)) != 'q');
return 0;
}
//进行自定义的腐蚀和膨胀操作
void Process()
{
Mat element = getStructuringElement(MORPH_RECT, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));
if (g_erodeOrDilate==0) {
erode(g_srcImage, g_dstImage, element);
}
else {
dilate(g_srcImage, g_dstImage, element);
}
imshow("【效果图】", g_dstImage);
}
void on_TrackbarNumChange(int, void *)
{
Process();
}
void on_ElementSizeChange(int, void *)
{
Process();
}
源码:
#include
#include
using namespace cv;
using namespace std;
Mat g_srcImage, g_dstImage, g_grayImage, g_maskImage; //定义原始图,目标图,灰度图,掩码图
int g_nFillMode = 1; //漫水填充的模式
int g_nLowDifference = 20, g_nUpDifference = 20; //负差最大值、正差最大值
int g_nConnectivity = 4; //表示floodFill函数标识符低八位的连通值
int g_bIsColor = true; //是否为彩色图
bool g_bUseMask = false; //是否显示掩模窗口
int g_nNewMaskVal = 255; //重新绘制的像素值
static void onMouse(int event, int x, int y, int, void*);
int main()
{
g_srcImage = imread("poster_home.jpg");
g_dstImage=g_srcImage.clone();
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
g_maskImage.create(g_srcImage.rows+2, g_srcImage.cols+2, CV_8UC1);
namedWindow("【效果图】");
createTrackbar("负差最大值", "【效果图】", &g_nLowDifference, 255, 0); //Trackbar
createTrackbar("正差最大值", "【效果图】", &g_nUpDifference, 255, 0);
setMouseCallback("【效果图】", onMouse, 0); //鼠标回调函数
while (1) //循环轮询按键
{
imshow("【效果图】", g_bIsColor ? g_dstImage:g_grayImage);
int c = waitKey(0); //获取键盘按键
if ((char)c == 27)
{
cout << "程序退出........." << endl;
break;
}
switch ((char)c)
{
case'1':
if (g_bIsColor) {
cout << "键盘'1'被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】" << endl;
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
g_maskImage = Scalar::all(0);
g_bIsColor = false;
}
else {
cout << "键盘'1'被按下,切换彩色/灰度模式,当前操作为将【灰度模式】切换为【彩色模式】" << endl;
g_srcImage.copyTo(g_dstImage);
g_maskImage = Scalar::all(0);
g_bIsColor = true;
}
break;
case'2':
if (g_bUseMask) {
destroyWindow("【mask】");
g_bUseMask = false;
}
else {
namedWindow("【mask】", WINDOW_NORMAL);
g_maskImage = Scalar::all(0);
imshow("【mask】", g_maskImage);
g_bUseMask = true;
}
break;
case'3':
cout << "按键'3'被按下,恢复原始图像" << endl;
g_srcImage.copyTo(g_dstImage);
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
g_maskImage = Scalar::all(0);
break;
case'4': //此处空范围即上下像素差均为0
cout << "按键'4'被按下,使用空范围的漫水填充" << endl;
g_nFillMode = 0;
break;
case'5':
cout << "按键'5'被按下,使用渐变、固定范围的漫水填充" << endl;
g_nFillMode = 1;
break;
case'6':
cout << "按键'6'被按下,使用渐变、浮动范围的漫水填充" << endl;
g_nFillMode = 2;
break;
case'7':
cout << "按键'7'被按下,操作标志符的低八位使用4位的连接模式" << endl;
g_nConnectivity = 4;
break;
case'8':
cout << "按键'8'被按下,操作标志符的低八位使用8位的连接模式" << endl;
g_nConnectivity = 8;
break;
default:
break;
}
}
return 0;
}
static void onMouse(int event, int x, int y, int, void*)
{
if (event != EVENT_LBUTTONDOWN)
return;
//--------------------调用floodFill函数之前的参数准备部分--------------------
Point seed = Point(x, y);
int LowDifference = g_nFillMode == 0 ? 0 : g_nLowDifference; //空范围的漫水填充,此值设为0,否则设为全局的g_nLowDifference
int UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference;
int flags = g_nConnectivity + (g_nNewMaskVal<<8) + (g_nFillMode==1?FLOODFILL_FIXED_RANGE:0);
//随机生成bgr值
int b = (unsigned)theRNG() & 255; //生成随机值
int g = (unsigned)theRNG() & 255; //生成随机值
int r = (unsigned)theRNG() & 255; //生成随机值
Rect ccomp; //定义重绘区域的最小边界矩形区域
Scalar newVal = g_bIsColor ? Scalar(b, g, r) : Scalar(r*0.299+g*0.587+b*0.114);//在重绘区域像素的新值
Mat dst = g_bIsColor ? g_dstImage : g_grayImage; //目标图的赋值
int area;
//----------------正式调用floodFill函数--------------------------
if (g_bUseMask) {
threshold(g_maskImage, g_maskImage, 1, 128, THRESH_BINARY); //将之前的都变为灰色
area = floodFill(dst, g_maskImage, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),
Scalar(UpDifference, UpDifference, UpDifference), flags);
imshow("【mask】", g_maskImage);
}
else {
area = floodFill(dst, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),
Scalar(UpDifference, UpDifference, UpDifference), flags);
}
imshow("【效果图】", dst);
cout << area << " 个像素被重绘" << endl;
}
源码:
#include
#include
using namespace cv;
using namespace std;
#define WINDOW_NAME "【程序窗口】"
Mat g_srcImage, g_dstImage, g_tmpImage;
int main()
{
g_srcImage = imread("poster_car_1.jpg");
namedWindow(WINDOW_NAME);
imshow(WINDOW_NAME, g_srcImage);
g_tmpImage = g_srcImage;
g_dstImage = g_tmpImage;
int key = 0;
while (1) //轮询获取按键信息
{
key = waitKey(9); //读取键值到key变量中
switch (key) {
case 27: //按键ESC
case 'q':
return 0;
break;
case '1':
pyrUp(g_tmpImage, g_dstImage, Size(g_tmpImage.cols*2, g_tmpImage.rows*2));
cout << "检测到按键【1】被按下,开始进行基于【pyrUp】函数的图片放大:图片尺寸*2" << endl;
break;
case '2':
pyrDown(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2));
cout << "检测到按键【2】被按下,开始进行基于【pyrDown】函数的图片缩小:图片尺寸/2" << endl;
break;
case '3':
resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols * 2, g_tmpImage.rows * 2));
cout << "检测到按键【3】被按下,开始进行基于【resize】函数的图片放大:图片尺寸*2" << endl;
break;
case '4':
resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2));
cout << "检测到按键【4】被按下,开始进行基于【pyrUp】函数的图片缩小:图片尺寸/2" << endl;
break;
}
imshow(WINDOW_NAME, g_dstImage);
g_tmpImage = g_dstImage; //将dst赋值给tmp,方便下一次循环
}
return 0;
}
源码:
#include
#include
using namespace std;
using namespace cv;
void on_Threshold(int, void*);
#define WINDOW_NAME "【程序窗口】"
int g_nThresholdValue = 100;
int g_nThresholdType = 0;
Mat g_srcImage, g_grayImage, g_dstImage;
int main()
{
g_srcImage = imread("poster_landscape_1.jpg");
cvtColor(g_srcImage, g_grayImage, COLOR_RGB2GRAY);
namedWindow(WINDOW_NAME);
createTrackbar("模式", WINDOW_NAME, &g_nThresholdType, 4, on_Threshold);
createTrackbar("参数值", WINDOW_NAME, &g_nThresholdValue, 255, on_Threshold);
on_Threshold(0, 0);
while (waitKey(10) != 27);
return 0;
}
void on_Threshold(int, void*)
{
threshold(g_grayImage, g_dstImage, g_nThresholdValue, 255, g_nThresholdType);
imshow(WINDOW_NAME, g_dstImage);
}