Opencv基础操作

/**********(6)图像预处理***********/
1. 像素点操作和卷积
(1)利用指针访问(快)
    for(int y = 0;y < Row;y++)
    {
        for(int x = 0;x < Col;x++)
        {
            for(int c = 0;c < channel;c++)
            {
                srcimg.ptr<Vec3b>(y)[x][c] = 0; //srcimg.at<ushort>(i,j) = 0;
            }
        }
    }
2. 动态访问(慢)
    for(int y = 0;y < Row;y++)
    {
        for(int x = 0;x < Col;x++)
        {
            for(int c = 0;c < channel;c++)
            {
                srcImg.at<Vec3b>(x,y)[c] = 0;
            }
        }
    }

/**********(7)滤波操作***********/
Mat kernel = (Mat_<double>(3,3)<<
             -1,0,1,
             -2,0,2,
             -1,-0,1,
             );
Mat dst;
cv::filter2D(srcImg,dst,srcImg.depth(),kernel);
/**********(8)直方图处理***********/
vector<Mat> bgr_planes;
split(src,bgr_planes);
int histSize = 256;
//设置值的范围
float range[] = {0,256};
const float* histRange = {range};
//初始化时,清除直方图
bool uniform = true;
bool accumulate = false;
//创建Mat对象分别保存直方图,每个通道均为1
Mat b_hist,g_hist,r_hist;
calcHist(&bgr_planes[0],1,0,Mat(),b_hist,1,&histSize,&histRange,uniform,accumulate);
calcHist(&bgr_planes[1],1,0,Mat(),g_hist,1,&histSize,&histRange,uniform,accumulate);
calcHist(&bgr_planes[2],1,0,Mat(),r_hist,1,&histSize,&histRange,uniform,accumulate);
//创建一个图像histImage显示直方图
int hist_w = 512;int hist_h = 400;
int bin_w = cvRound((double)hist_w / histSize);
Mat histImage(hist_h,hist_w,CV_8UC3,Scalar(0,0,0));
//归一化直方图
normalize(b_hist,b_hist,0,histImage.rows,NORM_MINMAX,-1,Mat());
normalize(g_hist,g_hist,0,histImage.rows,NORM_MINMAX,-1,Mat());
normalize(r_hist,r_hist,0,histImage.rows,NORM_MINMAX,-1,Mat());
for(int i = 1;i < histSize;i++)
{
    line(histImage,Point(bin_w * (i - 1),hist_h - cvRound(b_hist.at<float>(i - 1))),
         Point(bin_w*(i),hist_h - cvRound(b_hist.at<float>(i)),
              Scalar(255,0,0),2,8,0);
    line(histImage,Point(bin_w * (i - 1),hist_h - cvRound(g_hist.at<float>(i - 1))),
         Point(bin_w*(i),hist_h - cvRound(g_hist.at<float>(i)),
              Scalar(0,255,0),2,8,0);
    line(histImage,Point(bin_w * (i - 1),hist_h - cvRound(r_hist.at<float>(i - 1))),
         Point(bin_w*(i),hist_h - cvRound(r_hist.at<float>(i)),
              Scalar(0,0,255),2,8,0);
}
/**********(9)直方图匹配***********/
Mat gray_hist;
void CalHistogram(Mat &img);
void HistMap(Mat& srcImg,Mat& dstImg);

int main()
{
    Mat srcImg = imread("D:\\01 Codes\\00_OpencvBaseCPlus\\Fighting\\1.jpg",1);
    Mat objImg = imread("D:\\01 Codes\\00_OpencvBaseCPlus\\Fighting\\2.jpg",1);
    Mat dstImg;

    if(!srcImg.data || !objImg.data)
    {
        cout << "Open picture error!" << endl;
    }
    //namedWindow("SrcImg",WINDOW_NORMAL);

    //namedWindow("objImg",WINDOW_NORMAL);


    //分割源图像通道
    vector<Mat> src_channels;
    Mat src_blue,src_green,src_red;
    split(srcImg,src_channels);
    src_blue = src_channels.at(0);
    src_green = src_channels.at(1);
    src_red = src_channels.at(2);

    //分割目标通道
    vector<Mat> obj_channels;
    Mat obj_blue,obj_green,obj_red;
    split(objImg,obj_channels);
    obj_blue = obj_channels.at(0);
    obj_green = obj_channels.at(1);
    obj_red = obj_channels.at(2);

    //分别对BGR通道进行直方图规定化操作
    HistMap(src_blue,obj_blue);
    HistMap(src_green,obj_green);
    HistMap(src_red,obj_red);

    //合并通道,输出结果
    merge(src_channels,dstImg);
    imshow("objImg",objImg);
    imshow("srcImg",srcImg);
    imshow("dstImg",dstImg);
    waitKey(0);
    return 0;
}

void CalHistogram(Mat &img)
{
    if(img.empty())
        return;
    //设定bin数目
    int histSize = 256;
    //设定取值范围
    float range[] = {0,256};
    const float* histRange = {range};
    calcHist(&img,1,0,Mat(),gray_hist,1,&histSize,&histRange);
}


void HistMap(Mat& srcImg,Mat& objImg)
{
    int i,j;
    double gray_temp = 0;
    double totalPixel;//像素总数

    //计算源图像直方图,并归一化到(0,1)
    CalHistogram(srcImg);
    totalPixel = srcImg.cols * srcImg.rows;
    double srcHist[256];
    for(i = 0;i < 256;i++)
    {
        srcHist[i] = gray_hist.at<float>(i) / totalPixel;
    }

    //计算源图像直方图的累计概率0~1
    double srcCountHist[256];
    for(i = 0;i < 256;i++)
    {
        gray_temp = 0;
        for(j = 0;j <= i;j++)
        {
            gray_temp += srcHist[j];
        }
        srcCountHist[i] = gray_temp;
    }


    //计算目标图像直方图
    CalHistogram(objImg);
    totalPixel = objImg.cols * objImg.rows;
    double objHist[256];
    for(i = 0;i < 256;i++)
    {
        objHist[i] = gray_hist.at<float>(i) / totalPixel;
    }
    //计算源图像直方图的累计概率0~1
    double objCountHist[256];
    for(i = 0;i < 256;i++)
    {
        gray_temp = 0;
        for(j = 0;j <= i;j++)
        {
            gray_temp += objHist[j];
        }
        objCountHist[i] = gray_temp;
    }


    //GML组映射
    double min = 1; //设置成一个≥1的数即可
    uchar map[256]; //输入到输出的映射关系
    uchar groop[256]; //分组序号
    for(i = 0;i < 256;i++)
    {
        groop[i] = -1; //初始化
    }
    for(i = 0;i < 256;i++)
    {
        if(objHist[i] == 0)
        {
            //如果该位置的直方图为0,则可以跳出这次循环,因为不会有点映射到这里
            if(i > 0)
                groop[i] = groop[i - 1];
            continue;
        }

        min = 1;
        for(j = 0;j < 256;j++)
        {
            if(abs(objCountHist[i] - srcCountHist[j]) < min)
            {
                min = abs(objCountHist[i] - srcCountHist[j]);
                groop[i] = j; //最接近的直方图位置(源图像),记录分组序号
            }
        }

        if(i == 0) //灰度值为0的情况有点特殊
        {
            for(int pos = 0;pos <= groop[i];pos++)
                map[pos] = 0;
        }
        else{
            for(int pos = groop[i - 1] + 1;pos <= groop[i];pos++)
                //属于同一组内的元素,映射到同一个灰度值
                map[pos] = i;//建立映射关系
        }
    }
    //根据映射关系进行点运算,修改源图像
    uchar* p = NULL;//用于遍历像素的指针
    int width = srcImg.cols;
    int height = srcImg.rows;
    for(i = 0; i < height; i++)
    {
        p = srcImg.ptr<uchar>(i);//获取第i行的首地址
        for(j = 0;j < width;j++)
        {
            p[j] = map[p[j]];
        }
    }
}
/**********(10)滤波操作***********/
GaussianBlur(src,out,Size(7,7),0,0);
medianBlur(src,out,7);
bilateralFilter(src,dst,9,60,15);
         
         
/**********(11)分割操作***********/       
全局阈值,自适应阈值,OTSU阈值,区域生长算法
         
         
/**********(12)鼠标单击选单点漫水填充算法***********/           
//对鼠标的动作进行处理
void on_MouseHandle(int event,int x,int y,int flags,void* param)
{
   //如果鼠标左键按下,则使用区域生长算法
   if(event == EVENT_LBUTTONDOWN)
   {
       //输出当前鼠标相对于图像的位置
       cout << x << " " <<y <<endl;
       //tmp = src.clone();
       floodFill(src,Point(x,y),Scalar(R,G,B),0,Scalar(dt,dt,dt),Scalar(dt,dt,dt));
       flag = true;
   }
}
         
         #define WINDOW_NAME "floodFill"
#define dt 1


Mat tmp;
Mat srcImg,src;
bool flag;
int R,G,B;
//对鼠标的动作进行处理
void on_MouseHandle(int event,int x,int y,int flags,void* param);

int main()
{
    srcImg = imread("D:\\01 Codes\\00_OpencvBaseCPlus\\Fighting\\3.jpg",1);

    Mat dstImg;

    if(!srcImg.data)
    {
        cout << "Open picture error!" << endl;
    }


    namedWindow("src",CV_WINDOW_AUTOSIZE);
    imshow("srcImg",srcImg);
    srcImg.copyTo(src);


    namedWindow(WINDOW_NAME);

    //设置鼠标控制函数
    createTrackbar("R",WINDOW_NAME,&R,255);
    createTrackbar("G",WINDOW_NAME,&G,255);
    createTrackbar("B",WINDOW_NAME,&B,255);

    setMouseCallback(WINDOW_NAME,on_MouseHandle,0);
    flag = true;

    cout<<srcImg.rows << "x" <<srcImg.cols << endl;

    while(1)
    {
        if(flag)
        {
            imshow(WINDOW_NAME,src);
            flag = false;
        }
        if(waitKey(10) == 'q')
            break;
    }
    //waitKey(0);
    return 0;
}
/**********(13)分水岭算法***********/  
//对鼠标的动作进行处理
static void on_Mouse(int event,int x,int y,int flags,void*);

Mat g_mMarkerMask,g_mImg;
Point prevPt(-1,-1);

namedWindow("image",1);
Mat imgGray;
srcImg.copyTo(g_mImg);
cvtColor(g_mImg,g_mMarkerMask,COLOR_BGR2GRAY);
cvtColor(g_mMarkerMask,imgGray,COLOR_GRAY2BGR);

g_mMarkerMask = Scalar::all(0);
imshow("image",g_mImg);

//设置鼠标操作函数
setMouseCallback("image",on_Mouse,0);
for(;;)
         {
             char c = (char)waitKey(0);
             if(c == 27)
                 break;
             //重置种子点集合
             if(c == 'r')
             {
                 g_mMarkerMask = Scalar::all(0);
                 srcImg.copyTo(g_mImg);
                 imshow("image",g_mImg);
             }
             if(c == 'w' || c == ' ')
             {
                 int i,j,compCount = 0;
                 vector<vector<Point>> contours;
                 vector<Vec4i> hierarchy;
                 //将鼠标选择的线条转换为种子点的位置
                 findContours(g_mMarkerMask,contours,hierarchy,RETR_CCOMP,CHAIN_APPROX_SIMPLE);
                 //查找轮廓
                 if(contours.empty())
                     continue;
                 Mat markers(g_mMarkerMask.size(),CV_32S);
                 markers = Scalar::all(0);
                 int idx = 0;
                 for(;idx >= 0;idx = hierarchy[idx][0],compCount++)
                     //绘制轮廓
                     drawContours(markers,contours,idx,Scalar::all(compCount+1),-1,8,hierarchy,INT_MAX);
                 if(compCount == 0)
                     continue;

                 //生成随机颜色,用于显示不同的分割区域
                 vector<Vec3b> colorTab;
                 for(int i = 0;i < compCount;i++)
                 {
                     int b = theRNG().uniform(0,255);
                     int g = theRNG().uniform(0,255);
                     int r = theRNG().uniform(0,255);
                     colorTab.push_back(Vec3b((uchar)b,(uchar)g,(uchar)r));
                 }

                 //调用分水岭算法函数
                 watershed(srcImg,markers);
                 Mat wshed(markers.size(),CV_8UC3);
                 //为分割后的区域上色
                 for(int i = 0;i < markers.rows;i++)
                 {
                     for(int j = 0;j < markers.cols;j++)
                     {
                         int index = markers.at<int>(i,j);
                         if(index == -1)
                         {
                             wshed.at<Vec3b>(i,j) = Vec3b(255,255,255);
                         }
                         else if(index <= 0 || index > compCount)
                         {
                             wshed.at<Vec3b>(i,j) = Vec3b(0,0,0);
                         }
                         else{
                             wshed.at<Vec3b>(i,j) = colorTab[index -1];
                         }
                     }
                 }
                 //与源图像合成,显示分割后的图像
                 wshed = wshed * 0.5 + imgGray * 0.5;
                 imshow("watershed transform",wshed);
             }

         }
         //对鼠标的动作进行处理
         static void on_Mouse(int event,int x,int y,int flags,void*)
         {
             //边界判断
             if(x < 0|| x >= g_mImg.cols || y < 0 || y >= g_mImg.rows)
                 return;

             //松开鼠标,初始化起点
             if(event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON)) //鼠标左键不是拖拽动作
             {
                 prevPt = Point(-1,-1);
             }
             //初始化起始点
             else if(event == EVENT_LBUTTONDOWN)
             {
                 prevPt = Point(x,y);
             }
             //移动鼠标,绘制移动轨迹,设置种子点
             else if(event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
             {
                 Point pt(x,y);
                 if(prevPt.x < 0)
                 {
                     prevPt = pt;
                 }
                 line(g_mMarkerMask,prevPt,pt,Scalar::all(255),5,8,0);
                 line(g_mImg,prevPt,pt,Scalar::all(255),5,8,0);
                 prevPt = pt;
                 imshow("image",g_mImg);
             }
         }
/**********(14)数字形态学***********/  
(1)腐蚀与膨胀
  快速消除图像中的小噪声块,都是对图像中的高亮区域进行“领域扩张”或者“领域缩小”;
(2)开运算和闭运算;
(3)形态学梯度:突出图像的外轮廓;
(4)顶帽:源图像与开运算结果图求差,开运算结果放大了裂缝或局部降低亮度的区域,背景提取功能;
(5)图像金字塔:图像多尺度表达的一张方式,高斯金字塔:向下采样,图像变小,拉普拉斯金字塔:向上重建上层未采样图像。
/**********(15) 边缘检测***********/  
Sobel算子:分为x方向和y方向完成;
Laplacian算子:模板不同,0,1,0,1,-4,1,0,1,0;求两阶导数,
Canny算法:
 (1)去噪
 (2)计算图像梯度幅值和方向
 (3)非极大值抑制
 (4)滞后阈值(高低阈值,小于排除,高于边缘,中间看周围是否有边缘点相连)
         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值