第五章 学习OpenCV——图像处理

第五章 学习OpenCV——图像处理

目录

  • 第五章 学习OpenCV图像处理
    • 目录
      • 例5-1 单一阈值与自适应阈值的比较
      • 例5-2 使用cvSmooth函数以多种方式平滑图像
      • 例5-3 cvErode腐蚀操作与cvDilate膨胀操作效果对比
      • 例5-4 在噪声图像中生成一个清晰的图像掩码
      • 例5-5 双边滤波操作
      • 例5-6 礼帽阈值化和图像金字塔操作
      • 例5-7 单一阈值化各方式与自适应阈值化比较

例5-1 单一阈值与自适应阈值的比较

针对有很强照明或反射梯度的图像,需要根据梯度梯度进行阈值化时,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;

}

运行结果如下图:
第五章 学习OpenCV——图像处理_第1张图片

例5-2 使用cvSmooth()函数以多种方式平滑图像

本例完成的工作如下:

 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;
}

运行结果如下图:
第五章 学习OpenCV——图像处理_第2张图片

例5-3 cvErode()腐蚀操作与cvDilate()膨胀操作效果对比

本例完成的工作如下:

 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;

}

运行结果如下图:
第五章 学习OpenCV——图像处理_第3张图片

例5-4 在噪声图像中生成一个清晰的图像掩码

本例完成的工作如下:

 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;
}

运行结果如下图:
第五章 学习OpenCV——图像处理_第4张图片

特别提醒:
笔者在编写此段代码时忽略了一些小细节,导致程序出现了许多意想不到的错误,错误如下:
错误1:ptr图像数据头指针,在CvMat中为uchar*, IplImage中为char*,如果此处将其类型强制转化为unchar*类型,程序能够正常工作,但是这样的做法并不严谨,可能会出现一些意想不到的问题。特别注意:像素点值的判断语句ptr[j] == val,当ptr类型为char*时,val必须为char型的数值,若使用int类型的值,将会出现如下图所示的错误(无法正常进行像素点值的判断):
第五章 学习OpenCV——图像处理_第5张图片
相关代码如下:

/******************遍历图像,指针算法********************/
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*类型),程序运行异常,笔者至今未能发现问题所在,希望能够解决的朋友不吝赐教,在此谢过。

例5-5 双边滤波操作

本例完成的工作如下:

 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;
}

运行结果如下图:
第五章 学习OpenCV——图像处理_第6张图片

例5-6 礼帽、阈值化和图像金字塔操作

本例完成的工作如下:

 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;
}

运行结果如下图:
第五章 学习OpenCV——图像处理_第7张图片

例5-7 单一阈值化各方式与自适应阈值化比较

本例完成的工作如下:

 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;
}

运行结果如下图:
第五章 学习OpenCV——图像处理_第8张图片

你可能感兴趣的:(OpenCV)