针对有很强照明或反射梯度的图像,需要根据梯度梯度进行阈值化时,cvAdaptiveThreshold()自适应阈值化比cvThreshold()单一阈值化具有更好的效果。具体代码如下:
#include
#include
#include
int main(int argc, char* argv[])
{
IplImage *Igray, *It, *Iat; //图像
double threshold = 25; //阈值
int threshold_type = CV_THRESH_BINARY; //阈值类型
int adaptive_method = CV_ADAPTIVE_THRESH_MEAN_C; //自适应方式
int block_size = 71; //区域大小
double offset = 15; //抵消的值
if ((Igray = cvLoadImage("D:\\Template\\OpenCV\\Template30_Threshold_Compare\\Debug\\1.jpg", CV_LOAD_IMAGE_GRAYSCALE) )== 0)
return -1;
It = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //二值阈值化图像
Iat = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //自适应阈值图像
cvThreshold(Igray, It, threshold, 255, threshold_type); //二值阈值化
cvAdaptiveThreshold(Igray, Iat, 255, adaptive_method, threshold_type, block_size, offset);
//自适应阈值化
cvNamedWindow("Raw", 1);
cvNamedWindow("Threshold", 1);
cvNamedWindow("Adaptive Threshold",1);
cvShowImage("Raw", Igray);
cvShowImage("Threshold", It);
cvShowImage("Adaptive Threshold", Iat);
cvWaitKey(0);
cvReleaseImage(&Igray);
cvReleaseImage(&It);
cvReleaseImage(&Iat);
cvDestroyWindow("Raw");
cvDestroyWindow("Threshold");
cvDestroyWindow("Adaptive Threshold");
return 0;
}
本例完成的工作如下:
1. 载入一个带有有趣纹理的图像;
2. 使用对称的平滑窗口,大小依次为3×3,5×5,9×9,11×11,并显示结果;
3. 用5×5高斯滤波器平滑图像两次和用两个11×11的平滑器平滑一次输出结果,对比显示;
4. 建立一个100×100的单通道图像,将图像全部像素设置为0,然后设置中心像素值等于255;
5. 利用5×5的高斯滤波器平滑此图像,并显示结果;
6. 利用9×9的高斯滤波器平滑此图像,并显示结果;
6. 重新对原始图像用5×5的高斯滤波器平滑两次,并显示结果;
7. 重新对原始图像用9×9的高斯滤波器平滑两次,并显示结果;
8. 设置param1=param2=9,依次将param3设置为1,4,6,进行高斯平滑,显示结果;
9. 设置param1=param2=0,依次将param3设置为1,4,6,进行高斯平滑,显示结果;
10. 设置param1=param2=0,param3=1,param4=9,进行高斯平滑,显示结果;
11. 设置param1=param2=0,param3=9,param4=1,进行高斯平滑,显示结果;
12. 设置param1=param2=0,param3=1,param4=9,平滑一次;再设置param1=param2=0,param3=9,param4=1,平滑一次,显示结果;
13. 设置param1=param2=0,param3=param4=9,平滑一次;再设置param1=param2=0,param3=param4=1,平滑一次,显示结果;
具体代码如下:
#include
#include
#include
int main(int argc, char* argv[])
{
IplImage *In, *Gaussian3_3, *Gaussian5_5, *Gaussian11_11,*Gaussian5_5_Double; //图像
IplImage *Gaussian_test1, *Gaussian_out1, *Gaussian_out2, *Gaussian_out3; //图像
IplImage *Gaussian_test2, *Gaussian_out_1, *Gaussian_out_2, *Gaussian_out_3; //图像
IplImage *Gaussian_out_4, *Gaussian_out_5, *Gaussian_out_6; //图像
IplImage *Gaussian_out_7, *Gaussian_out_8, *Gaussian_out_9, *Gaussian_out_10; //图像
int smooth_type = CV_GAUSSIAN; //阈值类型
if ((In = cvLoadImage("D:\\Template\\OpenCV\\Template31_Smooth_Compare\\Debug\\3.png")) == 0)
return -1;
Gaussian3_3 = cvCreateImage(cvGetSize(In), IPL_DEPTH_8U, 3); //高斯平滑图像3*3
Gaussian5_5 = cvCreateImage(cvGetSize(In), IPL_DEPTH_8U, 3); //高斯平滑图像5*5
Gaussian11_11 = cvCreateImage(cvGetSize(In), IPL_DEPTH_8U, 3); //高斯平滑图像11*11
Gaussian5_5_Double = cvCreateImage(cvGetSize(In), IPL_DEPTH_8U, 3); //高斯平滑图像5*5两次
Gaussian_test1 = cvCreateImage(cvSize(200,200), IPL_DEPTH_8U, 1); //原图像
Gaussian_out1 = cvCreateImage(cvSize(200, 200), IPL_DEPTH_8U, 1); //高斯平滑图像5*5
Gaussian_out2 = cvCreateImage(cvSize(200, 200), IPL_DEPTH_8U, 1); //高斯平滑图像9*9
Gaussian_out3 = cvCreateImage(cvSize(200, 200), IPL_DEPTH_8U, 1); //高斯平滑图像5*5两次
if ((Gaussian_test2 = cvLoadImage("D:\\Template\\OpenCV\\Template31_Smooth_Compare\\Debug\\5.jpg")) == 0)
return -2;
Gaussian_out_1 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3); //高斯平滑9*9 param3:1
Gaussian_out_2 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3); //高斯平滑9*9 param3:4
Gaussian_out_3 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3); //高斯平滑9*9 param3:6
Gaussian_out_4 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3); //高斯平滑0*0 param3:1
Gaussian_out_5 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3); //高斯平滑0*0 param3:4
Gaussian_out_6 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3); //高斯平滑0*0 param3:6
Gaussian_out_7 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3);
//高斯平滑0*0 param3:1 param4:9
Gaussian_out_8 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3);
//高斯平滑0*0 param3:9 param4:1
Gaussian_out_9 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3);
//第一次:高斯平滑0*0 param3:1 param4:9 第二次:高斯平滑0*0 param3:9 param4:1
Gaussian_out_10 = cvCreateImage(cvGetSize(Gaussian_test2), IPL_DEPTH_8U, 3);
//第一次:高斯平滑0*0 param3=param4=9 第二次:高斯平滑0*0 param3=param4=0
cvZero(Gaussian_test1); //清零
cvSetReal2D(Gaussian_test1, 100, 100, 255); //中心像素为255
cvSmooth(In, Gaussian3_3, smooth_type, 3, 3); //高斯平滑
cvSmooth(In, Gaussian5_5, smooth_type, 5, 5); //高斯平滑
cvSmooth(In, Gaussian11_11, smooth_type, 11, 11); //高斯平滑
cvSmooth(Gaussian5_5, Gaussian5_5_Double, smooth_type, 5, 5); //高斯平滑
cvSmooth(Gaussian_test1, Gaussian_out1, smooth_type, 5, 5); //高斯平滑
cvSmooth(Gaussian_test1, Gaussian_out2, smooth_type, 9, 9); //高斯平滑
cvSmooth(Gaussian_out1, Gaussian_out3, smooth_type, 5, 5); //高斯平滑
cvSmooth(Gaussian_test2, Gaussian_out_1, smooth_type, 9, 9, 1); //高斯平滑
cvSmooth(Gaussian_test2, Gaussian_out_2, smooth_type, 9, 9, 4); //高斯平滑
cvSmooth(Gaussian_test2, Gaussian_out_3, smooth_type, 9, 9, 6); //高斯平滑
cvSmooth(Gaussian_test2, Gaussian_out_4, smooth_type, 0, 0, 1); //高斯平滑
cvSmooth(Gaussian_test2, Gaussian_out_5, smooth_type, 0, 0, 4); //高斯平滑
cvSmooth(Gaussian_test2, Gaussian_out_6, smooth_type, 0, 0, 6); //高斯平滑
cvSmooth(Gaussian_test2, Gaussian_out_7, smooth_type, 0, 0, 1, 9); //高斯平滑
cvSmooth(Gaussian_test2, Gaussian_out_8, smooth_type, 0, 0, 9, 1); //高斯平滑
cvSmooth(Gaussian_out_7, Gaussian_out_9, smooth_type, 0, 0, 9, 1); //高斯平滑
cvSmooth(Gaussian_test2, Gaussian_out_10, smooth_type, 0, 0, 9, 9); //高斯平滑
cvSmooth(Gaussian_out_10, Gaussian_out_10, smooth_type, 0, 0, 1, 1); //高斯平滑
cvNamedWindow("In", 1);
cvNamedWindow("Gaussian3_3", 1);
cvNamedWindow("Gaussian5_5",1);
cvNamedWindow("Gaussian11_11", 1);
cvNamedWindow("Gaussian5_5_Double", 1);
cvNamedWindow("test1", 1);
cvNamedWindow("out1_5*5", 1);
cvNamedWindow("out2_9*9", 1);
cvNamedWindow("out3_5*5_D", 1);
cvNamedWindow("test2", 1);
cvNamedWindow("out_1_9*9_1", 1);
cvNamedWindow("out_2_9*9_4", 1);
cvNamedWindow("out_3_9*9_6", 1);
cvNamedWindow("out_4_0*0_1", 1);
cvNamedWindow("out_5_0*0_4", 1);
cvNamedWindow("out_6_0*0_6", 1);
cvNamedWindow("out_7_0*0_1_9", 1);
cvNamedWindow("out_8_0*0_9_1", 1);
cvNamedWindow("out_9_0*0_1_9_9_1", 1);
cvNamedWindow("out_10_0*0_9_9_0_0", 1);
cvShowImage("In", In);
cvShowImage("Gaussian3_3", Gaussian3_3);
cvShowImage("Gaussian5_5", Gaussian5_5);
cvShowImage("Gaussian11_11", Gaussian11_11);
cvShowImage("Gaussian5_5_Double", Gaussian5_5_Double);
cvShowImage("test1", Gaussian_test1);
cvShowImage("out1_5*5", Gaussian_out1);
cvShowImage("out2_9*9", Gaussian_out2);
cvShowImage("out3_5*5_D", Gaussian_out3);
cvShowImage("test2", Gaussian_test2);
cvShowImage("out_1_9*9_1", Gaussian_out_1);
cvShowImage("out_2_9*9_4", Gaussian_out_2);
cvShowImage("out_3_9*9_6", Gaussian_out_3);
cvShowImage("out_4_0*0_1", Gaussian_out_4);
cvShowImage("out_5_0*0_4", Gaussian_out_5);
cvShowImage("out_6_0*0_6", Gaussian_out_6);
cvShowImage("out_7_0*0_1_9", Gaussian_out_7);
cvShowImage("out_8_0*0_9_1", Gaussian_out_8);
cvShowImage("out_9_0*0_1_9_9_1", Gaussian_out_9);
cvShowImage("out_10_0*0_9_9_0_0", Gaussian_out_10);
cvWaitKey(0);
cvReleaseImage(&In);
cvReleaseImage(&Gaussian3_3);
cvReleaseImage(&Gaussian5_5);
cvReleaseImage(&Gaussian11_11);
cvReleaseImage(&Gaussian5_5_Double);
cvReleaseImage(&Gaussian_test1);
cvReleaseImage(&Gaussian_out1);
cvReleaseImage(&Gaussian_out2);
cvReleaseImage(&Gaussian_out3);
cvReleaseImage(&Gaussian_test2);
cvReleaseImage(&Gaussian_out_1);
cvReleaseImage(&Gaussian_out_2);
cvReleaseImage(&Gaussian_out_3);
cvReleaseImage(&Gaussian_out_4);
cvReleaseImage(&Gaussian_out_5);
cvReleaseImage(&Gaussian_out_6);
cvReleaseImage(&Gaussian_out_7);
cvReleaseImage(&Gaussian_out_8);
cvReleaseImage(&Gaussian_out_9);
cvReleaseImage(&Gaussian_out_10);
cvDestroyWindow("In");
cvDestroyWindow("Gaussian3_3");
cvDestroyWindow("Gaussian5_5");
cvDestroyWindow("Gaussian11_11");
cvDestroyWindow("Gaussian5_5_Double");
cvDestroyWindow("test1");
cvDestroyWindow("out3_5*5");
cvDestroyWindow("out3_9*9");
cvDestroyWindow("out3_5*5_D");
cvDestroyWindow("test2");
cvDestroyWindow("out_1_9*9_1");
cvDestroyWindow("out_2_9*9_4");
cvDestroyWindow("out_3_9*9_6");
cvDestroyWindow("out_4_0*0_1");
cvDestroyWindow("out_5_0*0_4");
cvDestroyWindow("out_6_0*0_6");
cvDestroyWindow("out_7_0*0_1_9");
cvDestroyWindow("out_8_0*0_9_1");
cvDestroyWindow("out_9_0*0_1_9_9_1");
cvDestroyWindow("out_10_0*0_9_9_0_0");
return 0;
}
本例完成的工作如下:
1. 用摄像机拍摄同一场景的两幅图片,拍摄位置略微不同,载入两幅图像,分别记为src1和src2;
2. 将src1减去src2并求绝对值,将结果记为diff12,并显示结果;
3. 对diff12先进行cvErode()腐蚀操作,然后进行cvDilate()膨胀操作,结果记为cleandiff,并显示结果;
4. 对diff12先进行cvDilate()膨胀操作,然后进行cvErode()腐蚀操作,结果记为dirtydiff,并显示结果;
具体代码如下:
#include
#include
#include
int main(int argc, char* argv[])
{
IplImage *In1, *In2, *diff12, *cleandiff, *dirtydiff; //图像
int smooth_type = CV_GAUSSIAN; //阈值类型
if ((In1 = cvLoadImage("D:\\Template\\OpenCV\\Template32_Erode_Dilate_Compare\\Debug\\1.jpg")) == 0)
return -1;
if ((In2 = cvLoadImage("D:\\Template\\OpenCV\\Template32_Erode_Dilate_Compare\\Debug\\2.jpg")) == 0)
return -2;
diff12 = cvCreateImage(cvGetSize(In2), IPL_DEPTH_8U, 3); //求差绝对值图像
cleandiff = cvCreateImage(cvGetSize(diff12), IPL_DEPTH_8U, 3); //开图像
dirtydiff = cvCreateImage(cvGetSize(diff12), IPL_DEPTH_8U, 3); //闭图像
cvAbsDiff(In1,In2,diff12); //两数组求差的绝对值
//先腐蚀后膨胀 开
cvErode(diff12, cleandiff, NULL, 1); //腐蚀,最小化,缩小、隔离亮区域
cvDilate(cleandiff, cleandiff, NULL, 1); //膨胀,最大化,扩展、连接亮区域
//先膨胀后腐蚀 闭
cvDilate(diff12, dirtydiff, NULL, 1); //膨胀,最大化,扩展、连接亮区域
cvErode(dirtydiff, dirtydiff, NULL, 1); //腐蚀,最小化,缩小、隔离亮区域
cvNamedWindow("In", 1);
cvNamedWindow("Diff12", 1);
cvNamedWindow("Erode",1);
cvNamedWindow("Dilate", 1);
cvShowImage("In", In1);
cvShowImage("Diff12", diff12);
cvShowImage("Erode", cleandiff);
cvShowImage("Dilate", dirtydiff);
cvWaitKey(0);
cvReleaseImage(&In1);
cvReleaseImage(&In2);
cvReleaseImage(&diff12);
cvReleaseImage(&cleandiff);
cvReleaseImage(&dirtydiff);
cvDestroyWindow("In");
cvDestroyWindow("Diff12");
cvDestroyWindow("Erode");
cvDestroyWindow("Dilate");
return 0;
}
本例完成的工作如下:
1. 用摄像机拍摄一张某场景的照片,然后摄像机不动,在此场景中心位置放一个咖啡杯,再拍摄一张照片,将其载入电脑,并转换为8位灰度图像;
2. 取其差的绝对值,并显示结果;
3. 对结果图像进行二值化阈值操作,剔除噪声的同时并保留咖啡杯。超过阈值的像素应该设置为255,并显示结果;
4. 在图像上进行cvMorphologyEx()的开运算CV_MOP_OPEN操作,进一步去除噪声,并显示结果;
5. 保留图像中最大的图形区域,在图像的左上角设置一个指针,然后让它遍历图像,当发现像素值为255时,存储其位置,然后对其进行漫水填充操作,新颜色值为100;
6. 读出漫水填充算法所返回的连续区域,并记录下面积,若图像中有另一个较大的区域,那么用0值对这个相对较小的区域进行颜色填充,然后删除已记录的面积和位置,并记录新区域的面积和位置;
7. 最后以颜色值255填充剩余的最大的区域,并显示结果;
8. 载入一张图像,使用之前步骤生成的掩码,在cvCopy()函数中使用此掩码,将杯子复制到新载入的图像之中。
具体代码如下:
#include
#include
#include
/******************遍历图像,指针算法********************/
bool find_point(IplImage *img, char val,CvPoint* point)
{
char* ptr=NULL;
// uchar* ptr = NULL;
/********** 错,CvMat中为uchar* IplImage中为char* ********/
if (img->nChannels == 1)
{
ptr = img->imageData;
if (ptr != NULL)
{
for (int i = 0; i < img->height; i++) //矩阵指针行寻址
{
ptr = (char*)(img->imageData + i*(img->widthStep)); //i 行 j 列
// ptr = (uchar*)img->imageData + i*img->widthStep; //index1 行 index2 列
/********** 错,mat中为uchar* IplImage中为char* ********/
for (int j = 0; j < img->width; j++) //矩阵指针列寻址
{
//if (ptr[j] == 255) /********错误 ptr对应的值为char型********/
if (ptr[j] == val) //判断某点像素是否为255
{
point->x = j; //列 ****Notice x为列坐标,若为行坐标会出现问题
point->y = i; //行
return true;
}
}
}
}
}
return false;
}
int main(int argc, char* argv[])
{
IplImage *In1, *In2, *In3;
IplImage *diff12, *Ithreshold, *temp, *Iopen; //图像
double threshold = 45; //阈值
int threshold_type = CV_THRESH_BINARY; //阈值类型
CvPoint Last_Point; //值为255点的上一点
CvPoint Current_Point; //值为255点当前点
int Last_Area = 0; //上一个区域面积
int Current_Area = 0; //当前区域面积
CvConnectedComp comp; //被填充区域统计属性
if ((In1 = cvLoadImage("D:\\Template\\OpenCV\\Template33_Threshold\\Debug\\5.jpg", CV_LOAD_IMAGE_GRAYSCALE)) == 0)
return -1;
if ((In2 = cvLoadImage("D:\\Template\\OpenCV\\Template33_Threshold\\Debug\\6.jpg", CV_LOAD_IMAGE_GRAYSCALE)) == 0)
return -2;
if ((In3 = cvLoadImage("D:\\Template\\OpenCV\\Template33_Threshold\\Debug\\7.jpg", CV_LOAD_IMAGE_GRAYSCALE)) == 0)
return -2;
Last_Point = cvPoint(0, 0); //初始化上一点
Current_Point = cvPoint(0, 0); //初始化当前点
diff12 = cvCreateImage(cvGetSize(In1), IPL_DEPTH_8U, 1); //求差绝对值图像
Ithreshold = cvCreateImage(cvGetSize(In1), IPL_DEPTH_8U, 1); //二值阈值化图像
temp = cvCreateImage(cvGetSize(In1), IPL_DEPTH_8U, 1); //临时图像
Iopen = cvCreateImage(cvGetSize(In1), IPL_DEPTH_8U, 1); //开运算图像
cvAbsDiff(In1,In2,diff12); //求差取绝对值
cvThreshold(diff12, Ithreshold, threshold, 255, threshold_type); //二值阈值化
cvMorphologyEx(Ithreshold, Iopen, temp, NULL, CV_MOP_OPEN, 2); //开运算
cvNamedWindow("Open", 1);
do
{
if (find_point(Iopen,255, &Current_Point)) //找像素值为255的像素点
{
cvFloodFill(Iopen, Current_Point, cvScalar(100), cvScalar(0), cvScalar(0),
&comp, 8 | CV_FLOODFILL_FIXED_RANGE); //对值为255的点进行漫水填充,值100
Current_Area = comp.area; //当前区域面积
if (Last_Area//当前区域大于上一区域,上一区域清0
{
if (Last_Area>0)
cvFloodFill(Iopen, Last_Point, cvScalar(0), cvScalar(0), cvScalar(0),
&comp, 8 | CV_FLOODFILL_FIXED_RANGE); //上一区域赋值0
cvShowImage("Open", Iopen);
cvWaitKey(500);
Last_Area = Current_Area; //当前区域赋值给上一区域
Last_Point = Current_Point; //当前点赋值给上一点
//memcpy(&Current_Point, &Last_Point, sizeof(CvPoint)); //错误,此方法复制无法正常使用掩码
}
else //当前区域小于等于上一区域,当前区域清0
{
if (Current_Area>0)
cvFloodFill(Iopen, Current_Point, cvScalar(0), cvScalar(0), cvScalar(0),
&comp, 8 | CV_FLOODFILL_FIXED_RANGE); //当前区域赋值0
cvShowImage("Open", Iopen);
cvWaitKey(500);
}
}
else //最后剩余的最大区域赋值255
{
cvFloodFill(Iopen, Last_Point, cvScalar(255), cvScalar(0), cvScalar(0), &comp, 8 | CV_FLOODFILL_FIXED_RANGE);
cvShowImage("Open", Iopen);
cvWaitKey(500);
break;
}
} while (true);
cvCopy(In1, In3, Iopen); //将指定In1掩码区域复制到In3内
cvNamedWindow("Input", 1);
cvNamedWindow("Diff", 1);
cvNamedWindow("Threshold",1);
cvNamedWindow("Mask", 1);
cvShowImage("Input", In1);
cvShowImage("Diff", diff12);
cvShowImage("Threshold", Ithreshold);
cvShowImage("Open", Iopen);
cvShowImage("Mask", In3);
cvWaitKey(0);
cvReleaseImage(&In1);
cvReleaseImage(&In2);
cvReleaseImage(&In3);
cvReleaseImage(&diff12);
cvReleaseImage(&Ithreshold);
cvReleaseImage(&Iopen);
cvDestroyWindow("Input");
cvDestroyWindow("Diff");
cvDestroyWindow("Threshold");
cvDestroyWindow("Open");
cvDestroyWindow("Mask");
return 0;
}
特别提醒:
笔者在编写此段代码时忽略了一些小细节,导致程序出现了许多意想不到的错误,错误如下:
错误1:ptr图像数据头指针,在CvMat中为uchar*, IplImage中为char*,如果此处将其类型强制转化为unchar*类型,程序能够正常工作,但是这样的做法并不严谨,可能会出现一些意想不到的问题。特别注意:像素点值的判断语句ptr[j] == val,当ptr类型为char*时,val必须为char型的数值,若使用int类型的值,将会出现如下图所示的错误(无法正常进行像素点值的判断):
相关代码如下:
/******************遍历图像,指针算法********************/
bool find_point(IplImage *img, char val,CvPoint* P_point)
{
char* ptr=NULL;
//uchar* ptr = NULL;
/********** 错,CvMat中为uchar* IplImage中为char* ********/
if (img->nChannels == 1)
{
ptr = img->imageData;
//ptr = (uchar*)img->imageData;
/********** 错,CvMat中为uchar* IplImage中为char* ********/
if (ptr != NULL)
{
for (int i = 0; i < img->height; i++) //矩阵指针行寻址
{
ptr = (img->imageData + i*(img->widthStep)); //i 行 j 列
//ptr = (uchar*)img->imageData + i*img->widthStep; //index1 行 index2 列
/********** 错,mat中为uchar* IplImage中为char* ********/
for (int j = 0; j < img->width; j++) //矩阵指针列寻址
{
//if (ptr[j] == 255) /********错误 ptr对应的值为char型********/
if (ptr[j] == val) //判断某点像素是否为255
{
P_point->x = j; //列 ****Notice x为列坐标,若为行坐标会出现问题
P_point->y = i; //行
//point.x = j; /********错误 无法正常实现行列赋值********/
//point.y = i;
return true;
}
}
}
}
}
return false;
}
错误2:获取指定像素点的坐标值时,要明确P_point->x为列坐标,P_point->y为行坐标,反了会出现一些意想不到的错误。
尚待解决的问题——point.x赋值结果与P_point->x赋值结果不同
笔者曾尝试使用矩阵中获取坐标值的方式point.x = j;获取行和列的值,但是其运行结果与P_point->x=j;的结果不同(其中,point为CvPoint类型,P_point为CvPoint*类型),程序运行异常,笔者至今未能发现问题所在,希望能够解决的朋友不吝赐教,在此谢过。
本例完成的工作如下:
1. 使用一个随机变量生成一个较小方差的随机图像,大部分值的差异不超过3,且大部分数值接近0;
2. 将此图像载入一个绘制程序例如PowerPoint,在图像上画一些辐射状相交于一个交点的线条;
3. 对此图像进行双边滤波操作,并显示结果。
具体代码如下:
#include
#include
#include
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
IplImage *In1,*In2,*Out; //图像
char* ptr; //图像数据指针
int smooth_type = CV_THRESH_BINARY; //模糊类型
int val=0; //叠加的值
In1 = cvCreateImage(cvSize(500, 500), IPL_DEPTH_8U, 1); //创建原始图像
Out = cvCreateImage(cvGetSize(In1), IPL_DEPTH_8U, 3); //创建输出图像
cvZero(In1); //清零
for (int i = 0; i < In1->height; i++) //矩阵指针行寻址
{
for (int j = 0; j < In1->width; j++) //矩阵指针列寻址
{
cvSetReal2D(In1, i, j, val); //设置图像元素的值
val++;
if (val == 4) //等于4清零
val = 0;
}
}
/******************打印矩阵********************/
//for (int i = 0; iheight; i++) //矩阵指针行寻址
//{
// for (int j = 0; jwidth; j++) //矩阵指针列寻址
// {
// double text = cvGetReal2D(In1, i, j); //获取i行j列元素值
// cout << text << " "; //空格
// }
// cout << endl; //换行
//}
cvNamedWindow("In1", 1);
cvNamedWindow("In2", 1);
cvNamedWindow("Out", 1);
cvShowImage("In1", In1);
cvSaveImage("D:\\Template\\OpenCV\\Template34_Bilate_Ral\\Debug\\0.jpg", In1);
In2=cvLoadImage("D:\\Template\\OpenCV\\Template34_Bilate_Ral\\Debug\\8.jpg");
cvShowImage("In2", In2);
cvSmooth(In2,Out,smooth_type,10,5);
cvShowImage("Out", Out);
cvWaitKey(0);
cvReleaseImage(&In1);
cvDestroyWindow("In1");
cvDestroyWindow("In2");
cvDestroyWindow("Out");
return 0;
}
本例完成的工作如下:
1. 读入一张风景图,将其转化为灰度图像;
2. 对此图像进行形态学“礼帽”操作,并显示其结果;
3. 将结果图像转化为8位的掩码(二值阈值化);
4. 复制灰度图像的灰度值到礼帽块中,并显示结果;
5. 利用cvResize()函数缩小图像,每个维度上缩小比例为2,因此整张图片缩小比例为4,重复三次,并显示结果;
6. 利用cvPyrdown()函数在原图像上进行三次降采样操作,并显示结果;
7. 对一幅风景图执行金字塔图像分割cvPyrSegmentation()操作。
具体代码如下:
#include
#include
#include
#include
#include
//#pragma comment(lib, "opencv_legacy244.lib")
IplImage* doResize(IplImage* in, int intermetod) //高斯滤波器大小,平滑作用
{
assert(in->width % 2 == 0 && in->height % 2 == 0); //断言,图像像素必须为偶数
IplImage* out = cvCreateImage(cvSize(in->width / 2, in->height / 2), in->depth, in->nChannels);
cvResize(in, out, intermetod); //缩小图像为1/2
return(out);
}
IplImage* doPyrDown(IplImage* in, int filter = IPL_GAUSSIAN_5x5) //高斯滤波器大小,平滑作用
{
assert(in->width % 2 == 0 && in->height % 2 == 0); //断言,图像像素必须为偶数
IplImage* out = cvCreateImage(cvSize(in->width / 2, in->height / 2), in->depth, in->nChannels);
cvPyrDown(in, out); //缩小图像为1/2
return(out);
}
int main(int argc, char* argv[])
{
IplImage *In1, *In2, *In3;
IplImage *Itophat, *Imask,*Itophat_gray;
IplImage *Iresize, *Ipyrdown;
IplImage *Isegmentation;
double threshold = 50; //阈值
int threshold_type = CV_THRESH_BINARY; //阈值类型
CvMemStorage *storage = cvCreateMemStorage(0); //分配存储区域
CvSeq *comp = NULL; //存储分割结果的详细信息
int level = 2; //金字塔层数
double threshold1 = 100; //阈值1,建立连接的错误阈值
double threshold2 = 200; //阈值2,分割簇的错误阈值
if ((In1 = cvLoadImage("D:\\Template\\OpenCV\\Template35_Tophat_Size_Segmentation\\Debug\\8.jpg", CV_LOAD_IMAGE_GRAYSCALE)) == 0)
return -1;
if ((In2 = cvLoadImage("D:\\Template\\OpenCV\\Template35_Tophat_Size_Segmentation\\Debug\\9.jpg")) == 0)
return -2;
if ((In3 = cvLoadImage("D:\\Template\\OpenCV\\Template35_Tophat_Size_Segmentation\\Debug\\8.jpg")) == 0)
return -3;
Itophat = cvCreateImage(cvGetSize(In1), IPL_DEPTH_8U, 1); //礼帽图像
Imask = cvCreateImage(cvGetSize(In1), IPL_DEPTH_8U, 1); //掩码图像
Itophat_gray = cvCreateImage(cvGetSize(In1), IPL_DEPTH_8U, 1); //礼帽块+灰度图像
Iresize = cvCreateImage(cvSize(In2->width / 8, In2->height / 8), In2->depth, In2->nChannels);
Ipyrdown = cvCreateImage(cvSize(In2->width / 8, In2->height / 8), In2->depth, In2->nChannels);
Isegmentation = cvCreateImage(cvSize(In3->width, In3->height), In3->depth, In3->nChannels);
cvMorphologyEx(In1, Itophat,NULL, NULL, CV_MOP_TOPHAT, 5); //礼帽 in place 需要temp
cvThreshold(Itophat, Imask, threshold, 255, threshold_type); //二值阈值化,一个8位掩码
cvCopy(Itophat, Itophat_gray); //礼帽块
cvCopy(In1, Itophat_gray, Imask); //将灰度值复制到礼帽块中
Iresize=doResize(In2, CV_INTER_NN); //每个维度缩小比例2
Iresize = doResize(Iresize, CV_INTER_NN);
Iresize = doResize(Iresize, CV_INTER_NN);
Ipyrdown = doPyrDown(In2, CV_INTER_NN); //图像金字塔降采样
Ipyrdown = doPyrDown(Ipyrdown, CV_INTER_NN);
Ipyrdown = doPyrDown(Ipyrdown, CV_INTER_NN);
cvPyrSegmentation(In3, Isegmentation, storage, &comp, level, threshold1, threshold2);
//图像分割
cvNamedWindow("Input", 1);
cvNamedWindow("Itophat", 1);
cvNamedWindow("Imask", 1);
cvNamedWindow("Itophat_gray", 1);
cvNamedWindow("Iresize", 1);
cvNamedWindow("Ipyrdown", 1);
cvNamedWindow("Input3", 1);
cvNamedWindow("Isegmentation", 1);
cvShowImage("Input", In1);
cvShowImage("Itophat", Itophat);
cvShowImage("Imask", Imask);
cvShowImage("Itophat_gray", Itophat_gray);
cvShowImage("Iresize", Iresize);
cvShowImage("Ipyrdown", Ipyrdown);
cvShowImage("Input3", In3);
cvShowImage("Isegmentation", Isegmentation);
cvWaitKey(0);
cvReleaseImage(&In1);
cvReleaseImage(&In2);
cvReleaseImage(&In3);
cvReleaseImage(&Itophat);
cvReleaseImage(&Imask);
cvReleaseImage(&Itophat_gray);
cvReleaseImage(&Iresize);
cvReleaseImage(&Ipyrdown);
cvReleaseImage(&Isegmentation);
cvDestroyWindow("Input");
cvDestroyWindow("Itophat");
cvDestroyWindow("Imask");
cvDestroyWindow("Itophat_gray");
cvDestroyWindow("Iresize");
cvDestroyWindow("Ipyrdown");
cvDestroyWindow("Input3");
cvDestroyWindow("Isegmentation");
return 0;
}
本例完成的工作如下:
1. 载入一幅场景丰富的图像,使用cvThreshold()函数对其进行单一阈值化操作,设置阈值为128,使用二值阈值化(CV_THRESH_BINARY)、反向二值阈值化(CV_THRESH_BINARY_INV)、截断阈值化(CV_THRESH_TRUNC)、超过阈值归零(CV_THRESH_TOZERO_INV)、低于阈值归零(CV_THRESH_TOZERO)对图像进行操作,并显示结果;
2. 使用函数cvAdaptiveThreshold()进行自适应阈值化操作,分别设置param1=5、param1=0、param1=-5,并显示结果。
具体代码如下:
#include
#include
#include
int main(int argc, char* argv[])
{
IplImage *Igray, *Iat1, *Iat2, *Iat3; //图像
IplImage *Ibinary, *Ibinary_inv, *Itrunc; //图像
IplImage *Itozero_inv, *Itozero; //图像
double threshold = 118; //阈值
double max_value = 255; //最大值
int threshold_type1 = CV_THRESH_BINARY; //二值阈值化
int threshold_type2 = CV_THRESH_BINARY_INV; //反向二值阈值化
int threshold_type3 = CV_THRESH_TRUNC; //截断阈值化
int threshold_type4 = CV_THRESH_TOZERO_INV; //超过阈值归零
int threshold_type5 = CV_THRESH_TOZERO; //低于阈值归零
int adaptive_method = CV_ADAPTIVE_THRESH_MEAN_C; //自适应方式
int block_size = 5; //区域大小
double offset1 = 5; //抵消的值 param1
double offset2 = 0; //抵消的值
double offset3 = -5; //抵消的值
if ((Igray = cvLoadImage("D:\\Template\\OpenCV\\Template36_Threshold_All_Compare\\Debug\\3.jpg", CV_LOAD_IMAGE_GRAYSCALE) )== 0)
return -1;
Ibinary = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //二值阈值化图像
Ibinary_inv = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //反向二值阈值化图像
Itrunc = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //截断阈值化图像
Itozero_inv = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //超过阈值归零图像
Itozero = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //低于阈值归零图像
Iat1 = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //自适应阈值图像
Iat2 = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //自适应阈值图像
Iat3 = cvCreateImage(cvGetSize(Igray), IPL_DEPTH_8U, 1); //自适应阈值图像
cvThreshold(Igray, Ibinary, threshold, max_value, threshold_type1); //二值阈值化
cvThreshold(Igray, Ibinary_inv, threshold, max_value, threshold_type2); //反向二值阈值化
cvThreshold(Igray, Itrunc, threshold, max_value, threshold_type3); //截断阈值化
cvThreshold(Igray, Itozero_inv, threshold, max_value, threshold_type4); //超过阈值归零
cvThreshold(Igray, Itozero, threshold, max_value, threshold_type5); //低于阈值归零
cvAdaptiveThreshold(Igray, Iat1, max_value, adaptive_method,
threshold_type1, block_size, offset1); //自适应阈值化 param1=5
cvAdaptiveThreshold(Igray, Iat2, max_value, adaptive_method,
threshold_type1, block_size, offset2); //自适应阈值化 param1=0
cvAdaptiveThreshold(Igray, Iat3, max_value, adaptive_method,
threshold_type1, block_size, offset3); //自适应阈值化 param1=-5
cvNamedWindow("Input", 1);
cvNamedWindow("Ibinary", 1);
cvNamedWindow("Ibinary_inv", 1);
cvNamedWindow("Itrunc", 1);
cvNamedWindow("Itozero_inv", 1);
cvNamedWindow("Itozero", 1);
cvNamedWindow("Adaptive Threshold param1:5",1);
cvNamedWindow("Adaptive Threshold param1:0", 1);
cvNamedWindow("Adaptive Threshold param1:-5", 1);
cvShowImage("Input", Igray);
cvShowImage("Ibinary", Ibinary);
cvShowImage("Ibinary_inv", Ibinary_inv);
cvShowImage("Itrunc", Itrunc);
cvShowImage("Itozero_inv", Itozero_inv);
cvShowImage("Itozero", Itozero);
cvShowImage("Adaptive Threshold param1:5", Iat1);
cvShowImage("Adaptive Threshold param1:0", Iat2);
cvShowImage("Adaptive Threshold param1:-5", Iat3);
cvWaitKey(0);
cvReleaseImage(&Igray);
cvReleaseImage(&Ibinary);
cvReleaseImage(&Ibinary_inv);
cvReleaseImage(&Itrunc);
cvReleaseImage(&Itozero_inv);
cvReleaseImage(&Itozero);
cvReleaseImage(&Iat1);
cvReleaseImage(&Iat2);
cvReleaseImage(&Iat3);
cvDestroyWindow("Input");
cvDestroyWindow("Ibinary");
cvDestroyWindow("Ibinary_inv");
cvDestroyWindow("Itrunc");
cvDestroyWindow("Itozero_inv");
cvDestroyWindow("Itozero");
cvDestroyWindow("Adaptive Threshold");
cvDestroyWindow("Adaptive Threshold param1:5");
cvDestroyWindow("Adaptive Threshold param1:0");
cvDestroyWindow("Adaptive Threshold param1:-5");
return 0;
}