imuncle / imuncle.github.io

大叔的个人小站
https://imuncle.github.io/
78 stars 17 forks source link

OpenCV学习 #89

Open imuncle opened 4 years ago

imuncle commented 4 years ago

要实现嵌入式视觉开发,首先得把最强大最经典的OpenCV学会。

我参考的是毛星云主编的《OpenCV3编程入门》,过了一遍,记录了我比较关注的内容。学习时编写的源码如下:

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

const int g_nMaxAlphaValue = 100;   //Alpha值的最大值
int g_nAlphaValueSlider;    //滑动条对应的变量
double g_dAlphaValue;
double g_bBetaValue;

Mat g_srcImage1;
Mat g_srcImage2;
Mat g_srcImage;

Rect g_rectangle;
bool g_bDrawingBox = false; //是否进行绘制
RNG g_rng(12345);

int g_nContrastValue;   //对比度
int g_nBrightValue; //亮度值
Mat src_Image, dstImage;

//响应滑动条的回调函数
void on_Trackbar(int , void*)
{
    g_dAlphaValue = (double)g_nAlphaValueSlider/g_nMaxAlphaValue;//求出当前你alpha值相对于最大值的比值
    g_bBetaValue = 1.0 - g_dAlphaValue;
    addWeighted(g_srcImage1, g_dAlphaValue, g_srcImage2, g_bBetaValue, 0.0, g_srcImage);
    imshow("【滑动条】图像混合",g_srcImage);
}

//自定义的矩形绘制函数
void DrawRectangle(cv::Mat& img, cv::Rect box)
{
    rectangle(img, box.tl(), box.br(), Scalar(g_rng.uniform(0,255), g_rng.uniform(0,255), g_rng.uniform(0,255)));//随机颜色
}

//鼠标回调函数,根据不同的鼠标事件进行不同的鼠标操作
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
    Mat &image = *(cv::Mat*) param;
    switch(event)
    {
        //鼠标移动消息
        case EVENT_MOUSEMOVE:
        {
            if(g_bDrawingBox)
            {
                g_rectangle.width = x - g_rectangle.x;
                g_rectangle.height = y - g_rectangle.y;
            }
        }
        break;
        //左键按下消息
        case EVENT_LBUTTONDOWN:
        {
            g_bDrawingBox = true;
            g_rectangle = Rect(x,y,0,0);
        }
        break;
        //左键抬起消息
        case EVENT_LBUTTONUP:
        {
            g_bDrawingBox = false;
            if(g_rectangle.width < 0)
            {
                g_rectangle.x += g_rectangle.width;
                g_rectangle.width *= -1;
            }
            if(g_rectangle.height < 0)
            {
                g_rectangle.y += g_rectangle.height;
                g_rectangle.height *= -1;
            }
            DrawRectangle(image, g_rectangle);
        }
    }
}

//该表图像对比度和亮度值的回调函数
void on_ContrastAndBright(int, void *)
{
    for(int y=0; y<src_Image.rows;y++)
    {
        for(int x=0;x<src_Image.cols;x++)
        {
            for(int c=0;c<3;c++)
            {
                dstImage.at<Vec3b>(y,x)[c] = saturate_cast<uchar>((g_nContrastValue*0.01)*(src_Image.at<Vec3b>(y,x)[c]) + g_nBrightValue);
            }
        }
    }
    imshow("【亮度对比度】", dstImage);
}

int main() {
    Mat img = imread("../test.jpeg");
    Mat out;
//    boxFilter(img, out, -1, Size(5,5));
//    imshow("【均值滤波】",out);
//    GaussianBlur(img, out, Size(3,3), 0, 0);
//    imshow("【高斯滤波】", out);
    //imshow("【原图】腐蚀操作",img); //显示图像
//    medianBlur(img, out, 7);
//    imshow("【中值滤波】", out);
//    bilateralFilter(img, out, 2, 25*2, 25/2);
//    imshow("【双边滤波】",out);

    Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));//获取自定义内核
//    dilate(img, out, element);//膨胀
//    imshow("【膨胀操作】", out);
//    erode(img, out, element);
//    imshow("【腐蚀操作】", out);
//    morphologyEx(img, out, MORPH_ERODE, element);
//    imshow("【腐蚀操作】", out);
//    morphologyEx(img, out, MORPH_DILATE, element);
//    imshow("【膨胀操作】", out);
//    morphologyEx(img, out, MORPH_OPEN, element);
//    imshow("【开运算】", out);
//    morphologyEx(img, out, MORPH_CLOSE, element);
//    imshow("【闭运算】", out);
//    morphologyEx(img, out, MORPH_GRADIENT, element);
//    imshow("【形态学梯度】", out);
//    morphologyEx(img, out, MORPH_TOPHAT, element);
//    imshow("【顶帽】", out);
//    morphologyEx(img, out, MORPH_BLACKHAT, element);
//    imshow("【黑帽】", out);

    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y, dst;
    Sobel(img, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
    convertScaleAbs(grad_x, abs_grad_x);
    imshow("【效果图】x方向Sobel", abs_grad_x);
    Sobel(img, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
    convertScaleAbs(grad_y, abs_grad_y);
    imshow("【效果图】y方向Sobel", abs_grad_y);
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
    imshow("【效果图】整体方向SObel", dst);

//    Mat src_gray;
//    cvtColor(img, src_gray, COLOR_BGR2GRAY);
//    Laplacian(src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);
//    convertScaleAbs(dst, src_gray);
//    imshow("【拉普拉斯变换】", src_gray);

//    Scharr(img, grad_x, CV_16S, 1,0, 1, 0,BORDER_DEFAULT);
//    convertScaleAbs(grad_x, abs_grad_x);
//    Scharr(img, grad_y, CV_16S, 0,1, 1, 0,BORDER_DEFAULT);
//    convertScaleAbs(grad_y, abs_grad_y);
//    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
//    imshow("【Scharr滤波】", dst);

    Mat midImage;
//    Canny(img, midImage, 50, 200, 3);
//    cvtColor(midImage, dst, CV_GRAY2BGR);
//    vector<Vec2f> lines;
//    HoughLines(midImage, lines, 1, CV_PI/180, 150, 0, 0);//霍夫变换找直线
//    for(size_t i=0;i<lines.size();i++)
//    {
//        float rho = lines[i][0], theta = lines[i][1];
//        Point pt1, pt2;
//        double a = cos(theta), b = sin(theta);
//        double x0 = a*rho, y0 = b*rho;
//        pt1.x = cvRound(x0 + 1000*(-b));
//        pt1.y = cvRound(y0 + 1000*(a));
//        pt2.x = cvRound(x0 - 1000*(-b));
//        pt2.y = cvRound(y0 - 1000*(a));
//        line(img, pt1, pt2, Scalar(55,100,195),     1, LINE_AA);
//    }
//    imshow("【霍夫变换】寻找直线", img);

//    cvtColor(img, midImage, COLOR_BGR2GRAY);
//    GaussianBlur(midImage, midImage, Size(9,9), 2, 2);
//    vector<Vec3f> circles;
//    HoughCircles(midImage, circles, HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);//霍夫变换寻找圆圈
//    for(size_t i = 0;i<circles.size();i++)
//    {
//        Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
//        int radius = cvRound(circles[i][2]);
//        circle(img, center, 3, Scalar(0,255,0), -1, 8, 0);
//        circle(img, center, radius, Scalar(155,50,255),3,8,0);
//    }
//    imshow("【霍夫变换】寻找圆圈", img);

//    cvtColor(img, img, COLOR_BGR2GRAY);
//    imshow("【原始图】", img);
//    equalizeHist(img, dst);
//    imshow("【直方图均衡化】", dst);

//    img = imread("../test1.jpeg", 0);
//    imshow("原始图", img);
//    dst = Mat::zeros(img.rows, img.cols, CV_8UC3);
//    img = img > 119;
//    imshow("【取阈值后】", img);
//    vector<vector<Point>> contours;
//    vector<Vec4i> hierarchy;
//    findContours(img, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
//    int index = 0;
//    for(; index>=0;index = hierarchy[index][0])
//    {
//        Scalar color(rand()&255, rand()&255, rand()&255);
//        drawContours(dst, contours, index, color, FILLED, 8, hierarchy);
//    }
//    imshow("【轮廓图】", dst);

//    Mat hsvImage;
//    cvtColor(img, hsvImage, COLOR_BGR2HSV);
//    int hueBinNum = 30;//色调的直方图直条数量
//    int saturationBinNum = 32;//饱和度的直方图直条数量
//    int histSize[] = {hueBinNum, saturationBinNum};
//    float hueRanges[] = {0,180};//定义色调变化范围为0~179
//    float saturationRanges[] = {0, 256};//定义饱和度的变化范围为0到255
//    const float * ranges[] = {hueRanges, saturationRanges};
//    MatND dstHist;
//    int channels[] = {0, 1};
//    calcHist(&hsvImage, 1, channels, Mat(), dstHist, 2, histSize, ranges, true, false);
//    double  maxValue = 0;
//    minMaxLoc(dstHist, 0, &maxValue, 0, 0);
//    int scale = 10;
//    Mat histImg = Mat::zeros(saturationBinNum*scale, hueBinNum*10, CV_8UC3);
//    for(int hue = 0; hue<hueBinNum;hue++)
//    {
//        for(int saturation = 0; saturation<saturationBinNum;saturation++)
//        {
//            float binVAlue = dstHist.at<float>(hue, saturation);
//            int intensity = cvRound(binVAlue*255/maxValue);
//            rectangle(histImg, Point(hue*scale, saturation*scale), Point((hue+1)*scale-1, (saturation+1)*scale-1), Scalar::all(intensity), FILLED);
//        }
//    }
//    imshow("素材图", img);
//    imshow("H-S直方图", histImg);

//    Mat cornerStrength;//进行Harris角点检测
//    img = imread("../test.jpg", 0);
//    cornerStrength = Mat::zeros(img.size(), img.type());
//    cornerHarris(img, cornerStrength, 2, 3, 0.01);//有问题,会报错
//    Mat harrisCorner;
//    threshold(cornerStrength, harrisCorner, 0.00001, 255, THRESH_BINARY);
//    imshow("【角点检测】", harrisCorner);

    /* 腐蚀操作 */
    //Mat element = getStructuringElement(MORPH_RECT, Size(15,15));
    //Mat dstIamge;
    //erode(img, dstIamge, element);  //腐蚀图像
    //imshow("【效果图】腐蚀操作",dstIamge);   //显示腐蚀后的图像
    //blur(img, dstIamge, Size(7,7)); //图像均值滤波(模糊)
    //imshow("均值滤波【效果图】",dstIamge);   //显示滤波后的图像

    /* Canny边缘检测 */
    //Mat grayImage, edge;
    //cvtColor(img, grayImage, COLOR_BGR2GRAY);
    //blur(grayImage, edge, Size(3,3));   //先用3x3的内核来降噪
    //Canny(edge, edge, 3, 9, 3); //执行Canny边缘检测
    //imshow("【效果图】Canny边缘检测", edge);

    //printf("\t 当前使用的eOpenCV版本为 OpenCV %s",CV_VERSION);
    //imwrite("../Canny.jpeg", edge); //输出图片文件

    //waitKey(0); //等待任意按钮按下

//    namedWindow("【滑动条】图像混合");
//    g_srcImage1 = imread("../test.jpeg");
//    g_srcImage2 = imread("../test1.jpeg");
//    g_srcImage1 = g_srcImage1(Rect(0,0,g_srcImage2.cols, g_srcImage2.rows));
//    g_nAlphaValueSlider = 70;
//    char TrackbarName[50];
//    sprintf(TrackbarName, "透明值: ");
//    createTrackbar(TrackbarName, "【滑动条】图像混合", &g_nAlphaValueSlider, g_nMaxAlphaValue, on_Trackbar);
//    on_Trackbar(g_nAlphaValueSlider,0);
//
//    src_Image = imread("../test.jpeg");
//    dstImage = Mat::zeros(src_Image.size(), src_Image.type());
//    g_nContrastValue = 80;
//    g_nBrightValue = 80;
//    namedWindow("【亮度对比度】");
//    createTrackbar("对比度:", "【亮度对比度】", &g_nContrastValue, 300, on_ContrastAndBright);
//    createTrackbar("亮度:", "【亮度对比度】", &g_nBrightValue, 200, on_ContrastAndBright);
//    on_ContrastAndBright(g_nContrastValue, 0);
//    on_ContrastAndBright(g_nBrightValue, 0);
//
//    g_rectangle = Rect(-1, -1, 0,0);
//    Mat tempImage;
//    img.copyTo(tempImage);
//    namedWindow("【鼠标绘图】");
//    setMouseCallback("【鼠标绘图】",on_MouseHandle, (void *)&img);
//
//    while(1)
//    {
//        img.copyTo(tempImage);
//        if(g_bDrawingBox)
//            DrawRectangle(tempImage, g_rectangle);   //当进行绘制的标识符为真,则进行绘制
//        imshow("【鼠标绘图】",tempImage);
//        if(waitKey(10) == 27) break;
//    }

    waitKey(0);
    return 0;
}

代码里面主要是一些图像处理API及其用法,需要的时候来参考就行。