• C++ opencv 学习


    1、创建窗口

    c++写法:

    void test2()
    {
        Mat img = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        cout<<img.depth()<<" "<<img.channels()<<endl;
        namedWindow("new",cv::WINDOW_AUTOSIZE);
        imshow("new",img);
        waitKey(0);
        destroyAllWindows();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    python写法:

    def test():
        cv2.namedWindow('new', cv2.WINDOW_NORMAL)
        cv2.imshow('new', 0)
        key = cv2.waitKey(0)
        if key & 0xFF  == ord('q'):
            cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2、读取图片

    c++写法,操作图像,将图像转换为hsv然后调整亮度值,转换会BGR格式显示

    void test2()
    {
        Mat img = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        cout<<img.depth()<<" "<<img.channels()<<endl;
        namedWindow("new",cv::WINDOW_AUTOSIZE);
        imshow("new",img);
        waitKey(0);
    
        Mat gray,hsv;
        cvtColor(img,gray,cv::COLOR_BGR2GRAY);
        imshow("new",gray);
        waitKey(0);
    
        cvtColor(img,hsv,cv::COLOR_BGR2HSV);
        imshow("new",hsv);
        waitKey(0);
    
        Mat channels[3];
        // 将HSV图像分离为三个单独的通道,这将把HSV图像的三个通道分别存储在channels数组的不同元素中
        split(hsv,channels);
        int bright = 50;
        channels[2] += bright;
        // 将亮度通道的像素值限制在0到255之间,大于255截断为255
        threshold(channels[2],channels[2],255,255,cv::THRESH_TRUNC);
        // 将修改后的通道合并为单个图像
        cv::merge(channels, 3, hsv);
        Mat outputImage;
        cv::cvtColor(hsv, outputImage, cv::COLOR_HSV2BGR);
    
        imshow("new",outputImage);
        waitKey(0);
        destroyAllWindows();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    @param filename Name of file to be loaded.
    @param flags Flag that can take values of cv::ImreadModes
    
    CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR );
    
    flags标识符介绍:
    IMREAD_GRAYSCALE = 0, 灰度图
    IMREAD_COLOR = 1,原本是什么颜色就显示什么颜色
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    def test2():
        cv2.namedWindow('new', cv2.WINDOW_AUTOSIZE)
        img = cv2.imread(img_name, 1)
        cv2.imshow('new', img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    	cv2.imwrite('1.png',img)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、视频采集

    def test3():
        # cv2.namedWindow('new', cv2.WINDOW_AUTOSIZE)
        # 获取视频设置 
        cap = cv2.VideoCapture(0)
        while True:
            ret, frame = cap.read()
            cv2.imshow('video', frame)
            key = cv2.waitKey(10)
            if (key & 0xFF) == ord('q'):
                break
        cap.release()
        cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    录制视频

    def test4():
        fourcc = cv2.VideoWriter_fourcc(*'MJPG')
        vw = cv2.VideoWriter('./out.mp4', fourcc, 25, (1920, 1080))
        cap = cv2.VideoCapture(0)
    
        # 判断摄像头是否打开状态
        while cap.isOpened():
            ret, frame = cap.read()
            if ret == True:
                cv2.imshow('video', frame)
    
                # 写数据到多媒体文件
                vw.write(frame)
    
                key = cv2.waitKey(10)
                if (key & 0xFF) == ord('q'):
                    break
            else:
                break
        cap.release()
        cv2.release()
        cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述
    在这里插入图片描述

    import cv2
    
    
    # 色彩空间
    # hsv:色相、饱和度、明亮度
    # yuv:4:2:0 4:2:2 4:4:4
    
    def callback():
        pass
    
    def test7():
        cv2.namedWindow('color',cv2.WINDOW_NORMAL)
        img = cv2.imread('./1.png')
        colorspaces = [cv2.COLOR_BGR2RGBA,cv2.COLOR_BGR2BRGA,
                       cv2.COLOR_BGR2GRAY,cv2.COLOR_BGR2HSV_FULLL,
                       cv2.COLOR_BGR2YUV]
        cv2.createTrackbar('curcolor','color',0,len(colorspaces),callback)
        while True:
            index = cv2.getTrackbarPos('curcolor','color')
            cvt_img = cv2.cvtColor(img,colorspaces[index])
            cv2.imshow('color',img)
            key = cv2.waitKey(10)
            if key & 0xFF == ord('q'):
                break
        cv2.destroyAllWindows()
    
    if __name__ == '__main__':
        test7()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    4、Mat的使用

    深拷贝和浅拷贝

    void test3()
    {
        Mat img,m1,m2;
        img = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        // 克隆,深拷贝
        m1 = img.clone();
        img.copyTo(m2);
    
        // 创建空白图像
        Mat m3 = Mat::zeros(Size(8,8),CV_8UC1);
        // 创建全部为1的通道,如果创建的是3通道,则只有每个元素的第一个通道为1
        Mat m4 = Mat::ones(Size(8,8),CV_8UC3);
        cout<<m3.cols<<m3.rows<<m3.channels()<<endl;
    
        // 3通道时候:每个元素的第一个通道为1
        m4 = 127;
        // 给3个通道都复值
        m4 = Scalar(127,127,127);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    像素值操作:
    1、根据下标操作
    2、根据指针操作

    void test4()
    {
        // 像素遍历操作
        namedWindow("new",WINDOW_NORMAL);
        Mat img,gray;
        img = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        for(int i=0;i<img.rows;i++){
            for(int j=0;j<img.cols;j++){
                Vec3b bgr = img.at<Vec3b>(i,j);
                img.at<Vec3b>(i,j)[0] = 255 - bgr[0];
                img.at<Vec3b>(i,j)[1] = 255 - bgr[1];
                img.at<Vec3b>(i,j)[2] = 255 - bgr[2];
            }
        }
        imshow("new",img);
        waitKey(0);
    
        cvtColor(img,gray,cv::COLOR_BGR2GRAY);
        for(int i=0;i<gray.rows;i++){
            for(int j=0;j<gray.cols;j++){
                int pt = img.at<uchar>(i,j);
                img.at<uchar>(i,j) = 255 - pt;
            }
        }
        imshow("new",gray);
        waitKey(0);
    
        // 基于指针访问 速度更快
        for(int i=0;i<img.rows;i++){
            uchar *current_row = img.ptr<uchar>(i);
            for(int j=0;j<img.cols;j++){
                if(img.channels() == 1){
                    int pt = *current_row;
                    *current_row++ = 255 - pt;
                }else if(img.channels() == 3){
                    *current_row++ = 255 - *current_row;
                    *current_row++ = 255 - *current_row;
                    *current_row++ = 255 - *current_row;
                }
            }
        }
        destroyAllWindows();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    像素值的加减乘除

    void test5()
    {
        // 像素操作
        namedWindow("new",WINDOW_NORMAL);
        Mat img,gray;
        img = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
    
        Mat m = Mat::zeros(img.size(),img.type());
        m = Scalar(2,2,2);
        Mat dst;
    
        // 乘法运算,超过255的时候会截断
        multiply(img,m,dst);
    
        // 加法操作
        add(img,m,dst);
    
        // 减法
        subtract(img,m,dst);
    
        // 除法
        divide(img,m,dst);
    
        // saturate_cast会做一个范围判定,是否在uchar范围内
        // saturate_cast(p1,p2);
        imshow("new",dst);
        waitKey(0);
        destroyAllWindows();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    GUI操作

    void on_trac(int val,void *userdata)
    {
        Mat *data = (Mat*)userdata;
        Mat m = Mat::zeros(data->size(),data->type());
        m = Scalar(val,val,val);
    
        Mat dst;
        add(*data,m,dst);
        imshow("new",dst);
    }
    
    void test6()
    {
        namedWindow("new",WINDOW_AUTOSIZE);
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        int maxValue = 100;
        int light = 50;
        cout<<src.type()<<endl;
        createTrackbar("Value Bar","new",&light,maxValue,on_trac,(void *)(&src));
        on_trac(50,&src);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    addWeighted函数解释

    dst = src1 * alpha + src2 * beta + gamma
    
    • 1

    5、异或操作

    // 异或操作
    void test7()
    {
        Mat m1 = Mat::zeros(Size(255,255), CV_8UC3);
        Mat m2 = Mat::zeros(Size(255,255), CV_8UC3);
        rectangle(m1,Rect(100,100,80,80),Scalar(255,255,0),-1,LINE_8,0);
        rectangle(m2,Rect(130,130,80,80),Scalar(255,0,255),-1,LINE_8,0);
        imshow("new",m1);
        waitKey(0);
        imshow("new",m2);
        waitKey(0);
    
        Mat dst;
        // 按位与(都为真就为真)
        bitwise_and(m1,m2,dst);
        imshow("new",dst);
        waitKey(0);
    
        // 按位或(一个为真就为真)
        bitwise_or(m1,m2,dst);
        imshow("new",dst);
        waitKey(0);
    
        // 按位取反
        bitwise_not(m1,dst);
        imshow("new",dst);
        waitKey(0);
    
        // 异或(不同为真,相同为假)
        bitwise_xor(m1,m2,dst);
        imshow("new",dst);
        waitKey(0);
        destroyAllWindows();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    6、通道分离,通道合并

    // 通道分离,通道合并
    void test8()
    {
        namedWindow("new",WINDOW_AUTOSIZE);
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        imshow("new",src);
        waitKey(0);
        vector<Mat> mv;
        split(src,mv);
        imshow("new",mv[0]);
        waitKey(0);
        imshow("new",mv[1]);
        waitKey(0);
        imshow("new",mv[2]);
        waitKey(0);
    
        // 将蓝色和绿色通道全部置0,只保留红色通道,然后合并
        mv[0] = 0;
        mv[1] = 0;
        Mat dst;
        merge(mv,dst);
        imshow("new",dst);
        waitKey(0);
    
        // 通道融合
        // 第三个参数,0通道到2通道,1通道到1通道,2通道到0通道
        int from_to[] = {0,2,1,1,2,0};
        mixChannels(&src,1,&dst,1,from_to,3);
        imshow("new",dst);
        waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    7、色彩空间转换

    // 色彩空间转换
    void test9()
    {
        namedWindow("new",WINDOW_AUTOSIZE);
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/green.jpg");
        Mat dst,mask;
        cvtColor(src,dst,COLOR_BGR2HSV);
    
        // 出来一张2值化的图像,绿色背景是白色,人物是黑色
        inRange(dst,Scalar(35,43,46),Scalar(77,255,255),mask);
    
        Mat redback = Mat::zeros(src.size(),src.type());
        redback = Scalar(40,40,200);
    
        // 取放之后人物酒变成白色了,背景是黑色的
        bitwise_not(mask,mask);
    
        // 只拷贝不为0的区域,为0的区域不拷贝
        src.copyTo(redback,mask);
        imshow("new",redback);
        waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    8、最大值、最小值

    // 最大值、最小值
    // 均值,方差
    // 方差衡量数据集中值的离散程度,数据集中差异较小时,标准方差较小,差异较大时,方差较大(携带有效信息就越多)
    // 1、计算出均值
    // 2、计算每个元素与平均值的差的平方
    // 3、计算平方差的平均值,得到的平方差相加,然后除以数据点的总数
    // 4、取平方根:将平均平方差的值进行平方根运算,得到标准方差。

    void test10()
    {
        namedWindow("new",WINDOW_AUTOSIZE);
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/green.jpg",cv::IMREAD_GRAYSCALE);
        double minv,maxv;
        Point minLoc,maxLoc;
        minMaxLoc(src,&minv,&maxv,&minLoc,&maxLoc,Mat());
        cout<<"minv:"<<minv<<" maxv:"<<maxv<<" minLoc:"<<minLoc<<" maxLoc:"<<maxLoc<<endl;
        Mat mean,stddev;
        meanStdDev(src,mean,stddev);
        cout<<mean<<" "<<stddev<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    9、绘制图像

    void test11()
    {
        namedWindow("new",WINDOW_AUTOSIZE);
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/green.jpg",cv::IMREAD_COLOR);
        // 绘制矩形
        Mat bg = Mat::zeros(src.size(),src.type());
        Mat dst;
        Rect rect(100,100,200,200);
        rectangle(bg,rect,Scalar(20,20,255),2,LINE_8,0);
    
        // 绘制圆,圆心坐标Point,15是半径
        circle(src,Point(350,400),150,Scalar(255,0,0),2,LINE_8,0);
        // 图像融合
        addWeighted(src,0.7,bg,0.3,0,dst);
    
        // 绘制线 两个点的位置
        line(bg,Point(100,100),Point(350,400),Scalar(0,255,0),2,LINE_8,0);
    
        // 绘制椭圆
        RotatedRect rrt;
        rrt.center = Point(200,200);
        rrt.size = Size(100,200);
        rrt.angle = 0;
        ellipse(src,rrt,Scalar(0,255,255),2,8);
        imshow("new",dst);
        waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    10、多边形绘制

    // 多边形绘制
    void test13()
    {
        Mat bg = Mat::zeros(Size(512,512),CV_8UC3);
        Point p1(100,200);
        Point p2(350,100);
        Point p3(450,280);
        Point p4(320,450);
        Point p5(80,400);
        vector<Point> pts;
        pts.push_back(p1);
        pts.push_back(p2);
        pts.push_back(p3);
        pts.push_back(p4);
        pts.push_back(p5);
        polylines(bg,pts, true,Scalar(0,0,255),2,LINE_8,0);
        // 填充多边形
    //    fillPoly()
        imshow("new",bg);
        waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    11、随机数

    void test12()
    {
        Mat bg = Mat::zeros(Size(512,512),CV_8UC3);
        int w = bg.cols;
        int h = bg.rows;
        // 随机数
        RNG rng(12345);
        while (true){
            int c = waitKey(10);
            if(c == 27) break;
            int x1 = rng.uniform(0,w);
            int y1 = rng.uniform(0,h);
            int x2 = rng.uniform(0,w);
            int y2 = rng.uniform(0,h);
            // 每次画之前清理一下
            bg = Scalar(0,0,0);
            line(bg,Point(x1,y1),Point(x2,y2),
                 Scalar(rng.uniform(0,255)
                 ,rng.uniform(0,255),rng.uniform(0,255)),1,LINE_AA,0);
            imshow("new",bg);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    12、鼠标实时绘制矩形

    Point sp(-1, -1);
    Point ed(-1, -1);
    Mat temp;
    
    static void on_draw(int event, int x, int y, int flags, void* userdata)
    {
        Mat img = *((Mat*)userdata);
        if (event == EVENT_LBUTTONDOWN) {
            sp.x = x;
            sp.y = y;
            cout << "sp.x:" << sp.x << " sp.y:" << sp.y << endl;
        }
        else if (event == EVENT_LBUTTONUP) {
            ed.x = x;
            ed.y = y;
            cout << "ed.x:" << ed.x << " ed.y:" << ed.y << endl;
            int x1 = x - sp.x;
            int y1 = y - sp.y;
            if (x1 > 0 && y1 > 0) {
                Rect rect(sp.x, sp.y, x1, y1);
                temp.copyTo(img);
                imshow("ROI区域", img(rect));
                rectangle(img,rect,Scalar(0,0,255),2,8,0);
                imshow("new", img);
                sp.x = -1;
                sp.y = -1;
            }
        }
        else if (event == EVENT_MOUSEMOVE) {
            if (sp.x > 0 && sp.y > 0) {
                ed.x = x;
                ed.y = y;
                int dx = ed.x - sp.x;
                int dy = ed.y - sp.y;
                if (dx > 0 && dy > 0) {
                    Rect box(sp.x, sp.y, dx, dy);
                    temp.copyTo(img);
                    rectangle(img, box, Scalar(0, 0, 255), 2, 8, 0);
                    imshow("new", img);
                }
            }
        }
    }
    
    void test14()
    {
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        namedWindow("new", WINDOW_AUTOSIZE);
        setMouseCallback("new", on_draw, (void*)&src);
        src.copyTo(temp);
        imshow("new", src);
        waitKey(0);
        destroyAllWindows();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    13、归一化

    13、normalize归一化原理解释
    函数原型,归一化类型,常见的有NORM_L1, NORM_L2, NORM_INF, NORM_MINMAX,不同的norm计算方式不一样

    注意:
    alpha:如果norm_type为NORM_MINMAX ,则alpha为最小值或最大值;如果norm_type为其他类型,则为归一化要乘的系数
    beta:如果norm_type为NORM_MINMAX ,则beta为最小值或最大值;如果norm_type为其他类型,beta被忽略,此处不会被用到,一般传入0【重点】

    void cv::normalize    (    
    	InputArray     src,
    	InputOutputArray     dst,
    	double     alpha = 1,
    	double     beta = 0,
    	int     norm_type = NORM_L2,
    	int     dtype = -1,
    	InputArray     mask = noArray() 
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    13.1、NORM_L1

    输入值:
    [2, 3, 4;
     3, 4, 5;
     4, 5, 6]
     
    输出结果:
    [0.055555556, 0.083333336, 0.11111111;
     0.083333336, 0.11111111, 0.1388889;
     0.11111111, 0.1388889, 0.16666667]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    1、先求出norm
    公式:L1_norm = ∥src1∥L1=∑I|src1(I)|,即各数的绝对值之和
    2+3+4+5+3+4+5+4+5+6 = 36

    2、再求dst
    公式:dst = alphasrc/L1_norm
    dst[0] = 1
    2/ 36 = 0.055555556

    应用场景:机器学习、信号处理、图像去噪。
    用途:L2规范化倾向于使得所有元素的大小都差不多,这在避免过拟合(如机器学习中的权重衰减)、信号去噪(通过最小化能量)等场景中非常有用。
    优势:防止数据中的个别点对总体结果产生过大影响,提高模型的泛化能力。

    13.2、NORM_L2

    输出结果:
     [0.16012815, 0.24019222, 0.32025629;
     0.24019222, 0.32025629, 0.40032035;
     0.32025629, 0.40032035, 0.48038444]
    
    • 1
    • 2
    • 3
    • 4

    1、先求出norm
    公式:L2_norm = 矩阵中各元素的平方和的开方(欧几里德)(L2-范数)
    4+9+16+9+16+25+16+25+36 = 开平方之后 = 12.4899959967968

    2、再求dst
    公式:dst = alphasrc/L2_norm
    dst[0] = 1
    2/ 12.4899959967968= 0.16012815

    应用场景:稀疏编码、特征选择、压缩感知。
    用途:L1规范化倾向于产生稀疏的解,即大部分元素为零,少数元素非零。这在特征选择中特别有用,可以自动地忽略不重要的特征。
    优势:促进稀疏性,有助于提高模型的可解释性,减少模型复杂度。

    13.3、NORM_INF

    输出结果:
     [0.33333334, 0.5, 0.66666669;
     0.5, 0.66666669, 0.83333337;
     0.66666669, 0.83333337, 1]
    
    • 1
    • 2
    • 3
    • 4

    1、先求出norm
    INF_norm = 矩阵中所有元素的最大值max

    2.、再求dst
    公式:dst = alphasrc/INF_norm
    dst[0] = 1.0
    2/ 6 = 0.33333334

    应用场景:优化问题、数值计算。
    用途:限制数组或向量的无穷范数(即最大绝对值)。在某些优化问题中,可能需要将解的范围限制在一定界限内,使用NORM_INF规范化可以达到这一目的。
    优势:保证了数据中没有极端的大值,有利于数值稳定性

    13.4、NORM_MINMAX
    1、 alpha、beta分别为归一化后的最小值、最大值
    函数会自动判断哪个为最大值,最小值
    在这里插入图片描述

    输出结果: [0, 0.25, 0.5;
     0.25, 0.5, 0.75;
     0.5, 0.75, 1]
     
     min=2,max=6
     (1-0) * (2-2)/(6-2) + 0 =0
     (1-0) * (3-2)/(6-2) + 0 = 0.25
     (1-0) * (4-2)/(6-2) + 0 = 0.25
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    应用场景:图像处理、数据预处理。
    用途:将数据规范化到一个特定的范围内,常用于调整图像亮度和对比度,或在输入机器学习模型前将特征缩放到同一范围。这有助于提高算法的收敛速度和精度。
    优势:简单直观,易于实现,可以使数据分布更均匀。

    总结:

    NORM_MINMAX适用于需要将数据规范化到相同尺度的场景。
    NORM_INF适用于需要控制数据的最大值不超过特定阈值的场景。
    NORM_L1适用于需要稀疏解的场景,如特征选择或构建稀疏模型。
    NORM_L2适用于需要平滑解、防止过拟合的场景,如机器学习中的正则化处理。

    // 1、MINMAX
    void test15()
    {
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        namedWindow("new", WINDOW_AUTOSIZE);
    
        Mat img,img2;
        cout<<src.type()<<endl;
        src.convertTo(src,CV_32FC3);
        cout<<src.type()<<endl;
    
        normalize(src,img,1.0,0,NORM_MINMAX);
        // imshow想显示浮点数据,必须归一化0-1之间
        imshow("new",img);
        normalize(img,img2,255.0,0,NORM_MINMAX);
        img2.convertTo(img2,CV_8UC3);
        imshow("new1",img2);
        waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    14、resize操作

    // resize
    void test16()
    {
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        namedWindow("new", WINDOW_AUTOSIZE);
    
        Mat zoomin,zoomout;
        int w = src.cols;
        int h = src.rows;
        resize(src,zoomin,Size(w/2,h/2),0,0,INTER_LINEAR);
        resize(src,zoomout,Size(w*1.5,h*1.5),0,0,INTER_LINEAR);
        imshow("1",src);
        imshow("2",zoomin);
        imshow("3",zoomout);
        waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    15、旋转翻转

    void test17()
    {
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
    //    namedWindow("new", WINDOW_AUTOSIZE);
        Mat dst,left,m1,m3;
        flip(src,dst,0);
        flip(src,left,1);
        flip(src,m1,-1);
        imshow("上下翻转",dst);
        imshow("左右翻转",left);
        imshow("180度旋转",m1);
        waitKey(0);
    
        // 图像旋转
        Mat d,M;
        int w = src.cols;
        int h = src.rows;
        M = getRotationMatrix2D(Point2f(w/2,h/2),45,1.0);
        double cos = abs(M.at<double>(0,0));
        double sin = abs(M.at<double>(0,1));
    
        int nw = cos * w + sin * h;
        int nh = sin * w + cos * h;
        M.at<double>(0,2) += (nw/2-w/2);
        M.at<double>(1,2) += (nh/2-h/2);
        warpAffine(src,d,M,Size(nw,nh),INTER_LINEAR,0,Scalar(0,0,255));
        imshow("new",d);
        waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    16、视频操作

    
    void test18()
    {
        VideoCapture cap(0);
        Mat fram;
        while(true){
            cap.read(fram);
            if(fram.empty()){
                break;
            }
            flip(fram,fram,1);
            imshow("new",fram);
            int n = waitKey(10);
            if(n == 27){
                break;
            }
        }
        cap.release();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    17、模糊操作

    // 图像卷积模糊操作
    void test19()
    {
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        namedWindow("new", WINDOW_AUTOSIZE);
        Mat dst;
        blur(src,dst,Size(3,3),Point(-1,-1));
        imshow("new",dst);
        waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    18、高斯模糊操作

    // 高斯双边模糊
    void test21()
    {
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        namedWindow("new", WINDOW_AUTOSIZE);
        Mat dst;
        bilateralFilter(src,dst,0,100,10);
        imshow("new",dst);
        waitKey(0);
    }
    
    // 高斯模糊
    void test20()
    {
        Mat src = imread("/Users/zhulei/CLionProjects/opencv_test/1.jpg");
        namedWindow("new", WINDOW_AUTOSIZE);
        Rect rect(100,100,500,500);
        Mat roi = src(rect);
        GaussianBlur(roi,roi,Size(0,0),15);
        roi.copyTo(src(rect));
        imshow("new",src);
        waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    19、边缘填充:cv::copyMakeBorder()

    作用:在图像四周填充指定像素形成边框。

    在这里插入图片描述

    利用此函数,对图片进行padding操作

    void test5()
    {
    	int width = 384,height = 226;
    	Mat img = imread("H:\\face\\_00067cfb-e535423e.jpg");
    	
    	float rw = (float)width/img.cols;
    	float rh = (float)height/img.rows;
    	cout << "rw:" << rw << " rh:" << rh << endl;
    	
    	float min_ratoi = min(rw, rh);
    	// 384 * 216
    	 resize(img, img, Size(img.cols *min_ratoi, img.rows *min_ratoi));
    	//resize(img, img, Size(),min_ratoi,min_ratoi);
    	imshow("new", img);
    
    	// 边缘填充
    	int delta_width = width - img.cols;
    	int delta_height = height - img.rows;
    	int top = delta_height/2;
    	int bottom = delta_height -top;
    	int left = delta_width/2;
    	int right = delta_width-left;
    	cout << "del_width:" << delta_width << "del_height:" << delta_height << endl;
    	cout <<"top:"<< top <<"bottom:" << bottom<<"left:" << left<<"right:" << right << endl;
    	
    	RNG rng;
    	Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    
    	Mat m1, m2, m3, m4, m5, m6,m7,m8;
    	// 使用常数填充
    	copyMakeBorder(img, m1, top, bottom, left, right, BORDER_CONSTANT, color);
    	// 复制最边缘像素
    	copyMakeBorder(img, m2, top, bottom, left, right, BORDER_REPLICATE, color);
    	// 反射法。以两边为轴
    	copyMakeBorder(img, m3, top, bottom, left, right, BORDER_REFLECT, color);
    	// 环绕式填充
    	copyMakeBorder(img, m4, top, bottom, left, right, BORDER_WRAP, color);
    	// 反射(Reflect)边缘填充,也称为反射101。图像的边缘像素被复制,并且第二边缘内部的像素被镜像填充。
    	copyMakeBorder(img, m5, top, bottom, left, right, cv::BORDER_REFLECT_101, color);
    	// 反射(Reflect)边缘填充,图像的边缘像素被复制,并且第二边缘内部的像素被镜像填充
    	copyMakeBorder(img, m6, top, bottom, left, right, cv::BORDER_REFLECT101, color);
    	// 默认边缘填充方式
    	copyMakeBorder(img, m7, top, bottom, left, right, cv::BORDER_DEFAULT, color);
    	// 孤立边缘填充。每个通道被独立填充,而不考虑其他通道。
    	copyMakeBorder(img, m8, top, bottom, left, right, cv::BORDER_ISOLATED, color);
    	
    	imshow("new1", m1);
    	imshow("new2", m2);
    	imshow("new3", m3);
    	imshow("new4", m4);
    	imshow("new5", m5);
    	imshow("new6", m6);
    	imshow("new7", m7);
    	imshow("new8", m8);
    	waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    20、adaptiveThreshold函数

    在这里插入图片描述

    #include 
    函数说明:void cv::adaptiveThreshold( InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C );
    输入参数:
    				src					8位单通道图像。
    				dst					与src大小和类型相同的目标图像。
    				maxValue			指定给满足条件的像素的非零值
    				adaptiveMethod		自适应阈值算法。BORDER_REPLICATE|BORDER_ISOLATED用于处理边界。
    							cv::ADAPTIVE_THRESH_MEAN_C = 0 			窗口均值阈值法。计算出领域的平均值再减去参数double C的值
    							cv::ADAPTIVE_THRESH_GAUSSIAN_C = 1		高斯分布阈值法。计算出领域的高斯均值再减去参数double C的值
    				thresholdType		阈值化类型(只有两个取值)。
    							cv::THRESH_BINARY = 0 				若大于thresh,则设置为maxval,否则设置为0。(常用)
    							cv::THRESH_BINARY_INV = 1 			若大于thresh,则设置为0,否则设置为maxval(反操作)。
    				blockSize			像素邻域大小(单位):357,依此类推。自适应阈值算法的阈值计算时使用。
    				C					偏移值。自适应阈值算法的阈值计算时使用。
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    void test6()
    {
    	Mat img = imread("H:\\face\\_00067cfb-e535423e.jpg");
    	resize(img, img, Size(384, 226));
    	Mat srcGray;
    	cvtColor(img, srcGray, COLOR_BGR2GRAY);
    	cv::Mat ADAPTIVE_THRESH_MEAN_C0, ADAPTIVE_THRESH_MEAN_C1, ADAPTIVE_THRESH_GAUSSIAN_C0, ADAPTIVE_THRESH_GAUSSIAN_C1;
    	int blockSize = 5;
    	int constValue = 10;
    	const int maxVal = 255;
    	cv::adaptiveThreshold(srcGray, ADAPTIVE_THRESH_MEAN_C0, maxVal, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, blockSize, constValue);
    	cv::adaptiveThreshold(srcGray, ADAPTIVE_THRESH_MEAN_C1, maxVal, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, blockSize, constValue);
    	cv::adaptiveThreshold(srcGray, ADAPTIVE_THRESH_GAUSSIAN_C0, maxVal, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, blockSize, constValue);
    	cv::adaptiveThreshold(srcGray, ADAPTIVE_THRESH_GAUSSIAN_C1, maxVal, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, blockSize, constValue);
    
    	imshow("new1", ADAPTIVE_THRESH_MEAN_C0);
    	imshow("new2", ADAPTIVE_THRESH_MEAN_C1);
    	imshow("new3", ADAPTIVE_THRESH_GAUSSIAN_C0);
    	imshow("new4", ADAPTIVE_THRESH_GAUSSIAN_C1);
    	waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    【华为机试真题 JAVA】事件推送-100
    精华!一张图进阶 RocketMQ
    【强化学习】policy gradient的一些tips
    PAT 甲级 A1066 Root of AVL Tree
    001——体验鸿蒙(基于I.MAX6ULL)
    基于STFT和卷积神经网络的时序数据分类 代码+数据 可直接运行
    【Kafka面试演练】那Kafka消费者手动提交、自动提交有什么区别?
    如何写最基础的播放音频界面
    如何指定JVM target 为1.8
    最佳websocket封装
  • 原文地址:https://blog.csdn.net/weixin_45715405/article/details/136150074