• C++ Opencv 图片运算和处理


    色彩空间

    RGB 和 BGR

    opencv主要使用BGR,与其他显示设备RGB不同需注意,是产生颜色不对的原因所在。
    opencv Mat的type()值参照表

    -C1C21C3C4C(5)C(6)C(7)C(8)
    CV_8U08162432404856
    CV_8S19172533414957
    CV_16U210182634425058
    CV_16S311192735435159
    CV_32S412202836445260
    CV_32F513212937455361
    CV_64F614223038465462

    HSV 和 HSL

    HSV:H(Hue)表示色相,S(saturation)表示饱和度,V(value)明度
    在这里插入图片描述
    HSL:H(Hue)表示色相,S(saturation)表示饱和度,L(lightness)亮度
    在这里插入图片描述

    YUV

    YUV:主要用于视频处理,数据源Y代表灰色图像,U、V代表颜色

    YUV4:2:0 表示没4个Y里,要么有2个U,要么有2个V
    在这里插入图片描述

    划线

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    cv::Mat array2Img(nc::NdArray<uchar> array);
    
    void main(){
    	nc::NdArray<uchar> img_array = nc::NdArray<uchar>(40, 60);
       img_array.zeros();
        cv::Mat line_img;
        int count = 0;
        while (count < 30) {
            img_array(count ,9) = 255;      // blue
            img_array(count, 10) = 255;     // green
            img_array(count, 11) = 255;     // red
            count += 1;
        }
        for (size_t i = 0; i < img_array.numRows(); i++)
        {
            std::cout << "第" << i << ": ";
            for (size_t j = 0; j < img_array.numCols(); j++)
            {
                std::cout << (size_t)img_array(i, j);
            }
            std::cout << "\n";
        }
        line_img = array2Img(img_array);
        cv::namedWindow("line_img", cv::WINDOW_NORMAL);
        cv::imshow("line_img",line_img);
        cv::waitKey(0);
     }
     //数组转图片
    cv::Mat array2Img(nc::NdArray<uchar> array) {
        
        size_t h = array.numRows();
        size_t w = array.numCols();
    
        cv::Mat img(h,(size_t)(w/3), CV_8UC3);     //保存为RGB
        for (size_t i = 0; i < h; i++)
        {
            uchar* tmp = img.ptr<uchar>(i);
            for (size_t j = 0; j < w; j++)
            {
                tmp[j] = array(i, j);
            }
        }
        return img;
    }
    
    • 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

    在这里插入图片描述

    3通道分割和合并

    方法一

    	std::vector<cv::Mat> channelsSplistArray, channelsMergeArray;
        cv::Mat buleChannel, redChannel, greenChannel,newAddchannel,imgMerge;
        //分割, 相应通道颜色的会转为灰色
        cv::split(line_img, channelsSplistArray);    // &
        buleChannel = channelsSplistArray.at(0);     // 0   255 255
        greenChannel = channelsSplistArray.at(1);    // 255 0   255 
        redChannel = channelsSplistArray.at(2);      // 255 255 0
        cv::imshow("buleChannel", buleChannel);
        cv::imshow("greenChannel", greenChannel);
        cv::imshow("redChannel", redChannel);
        // 合并三通道 设置blue为0
        newAddchannel = channelsSplistArray.at(0).clone();
        newAddchannel.setTo(0);
        channelsMergeArray.push_back(newAddchannel);
        channelsMergeArray.push_back(greenChannel);
        channelsMergeArray.push_back(redChannel);
        cv::merge(channelsMergeArray, imgMerge);
        // 当通道设置为0 : 0为blue 1为green 2为red
        /*channelsSplistArray[0] = cv::Scalar(0);      
        cv::merge(channelsSplistArray, imgMerge);*/
        cv::imshow("imgMerge", imgMerge);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    方法二

    
        cv::Mat newAddchannel, imgMerge, imgChannelSplitArray[3];
        // 分割
        cv::split(line_img, imgChannelSplitArray);
        cv::imshow("buleChannel", imgChannelSplitArray[0]);
        cv::imshow("greenChannel", imgChannelSplitArray[1]);
        cv::imshow("redChannel", imgChannelSplitArray[2]);
        // 合并
        newAddchannel = imgChannelSplitArray[0].clone();
        newAddchannel.setTo(0);
        cv::Mat imgChannelMergeArray[3] = { newAddchannel,imgChannelSplitArray[1],imgChannelSplitArray[2]};
        cv::merge(imgChannelMergeArray, 3, imgMerge);
        cv::imshow("imgMerge", imgMerge);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    画图

    线

    //画线 line(img,起点, 终点, 线颜色, 线粗(-1为实心), 线平滑度, 起始点和终点成倍缩小)
        cv::line(line_img, { 10,20 }, { 500,500 }, { 0,255,255 },1,16);
    
    • 1
    • 2

    // 画圆 circle(img, 圆点, 半径, 线颜色, 线粗(-1为填充), 线平滑度, 按圆心和半径成倍缩小)
    cv::circle(line_img, { 30,30 }, 5, { 255,255,0 }, 1, 16,0);
    
    • 1
    • 2

    椭圆

    // 画椭圆 ellipse(img, 圆点, 椭圆的长宽的一半, 呈现的角度, 画椭圆的起点, 终点, 线颜色, 线粗(-1为填充), 线平滑度, 按圆心和椭圆成倍缩小)
    cv::ellipse(line_img, { 200,200 }, { 40,20 }, 0.0, 0.0, 360.0, { 0,255,255 }, 2, 16);
    
    • 1
    • 2

    多边形

    // 画多边形
        nc::NdArray<cv::Point> triangle_array = { {200,200},{250,200},{250,250} };      // 点集获取方式1
        std::vector<cv::Point> triangle_array2({ {200,200},{250,200},{250,250} });   // 点集获取方式2
        // 画边 polylines(img, 点集为std::vector类型的数组, 是否连接点集中的点, 颜色, 线粗, 线平滑度,按点集中的点成倍缩小)
        cv::polylines(line_img, triangle_array.toStlVector(), true, { 255,255,255 },5,16);
        // 填充 fillPoly(img, 点集为std::vector类型的数组, 颜色, 线平滑度,按点集中的点成倍缩小)
        cv::fillPoly(line_img, triangle_array2, { 255,0,255 });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    文本

    	// 画文本  putText(img, 文字内容, 坐标点, 文字类型, 文字大小, 文字颜色, 线粗, 线平滑度, 是否倒转)
    	cv::putText(line_img, "Hello world!", cv::Point(10, 400), cv::FONT_HERSHEY_DUPLEX, 1.0, { 255,255,255 }, 3, 16, true);
        cv::putText(line_img, "Hello world!", cv::Point(10, 450), cv::FONT_HERSHEY_DUPLEX, 1.0, { 255,255,255 }, 3, 16);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    图片运算

    加减乘除

    	cv::Mat cartoon = cv::imread("C:\\Users\\10358\\Pictures\\img\\3.jpg");
    	// std::cout << cartoon.size();		// 打印图片大小
    	// cv::Mat ones_img = cv::Mat::ones(cv::Size(394, 700), CV_8UC3) * 20;		// cv自带的ones类只能将blue通道赋值1
    	nc::NdArray<uchar> img_array = nc::NdArray<uchar>(700, 394*3).ones();
    	cv::Mat test_img= array2Img(img_array)*20;
    	cv::Mat add_img, sub_img, mul_img, div_img;
    	cv::add(test_img, cartoon, add_img);
    	cv::subtract(cartoon, test_img, sub_img);
    	cv::multiply(cartoon, test_img, mul_img);
    	cv::divide( cartoon, test_img, div_img);
    
    	cv::imshow("orig", cartoon);
    	cv::imshow("add_img", add_img);
    	cv::imshow("sub_img", sub_img);
    	cv::imshow("mul_img", mul_img);
    	cv::imshow("div_img", div_img);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    非、与、或、异或

    cv::Mat cartoon = cv::imread("C:\\Users\\10358\\Pictures\\img\\3.jpg");
    	// std::cout << cartoon.size();		// 打印图片大小
    	// cv::Mat ones_img = cv::Mat::ones(cv::Size(394, 700), CV_8UC3) * 20;		// cv自带的ones类只能将blue通道赋值1
    	nc::NdArray<uchar> img_array = nc::NdArray<uchar>(700, 394*3).ones();
    	cv::Mat test_img= array2Img(img_array)*20;
    	cv::Weight_img,not_img,and_img,or_img,xor_img;
    	cv::addWeighted(add_img, 0.8, mul_img, 0.2, 0, Weight_img);		// 图片的权重融合
    	cv::bitwise_not(cartoon, not_img);								// 图片非运算
    	cv::bitwise_and(test_img, cartoon,and_img);						// 图片与运算:只有1&&1为真,其余为假(0&&1,0&&0)
    	cv::bitwise_or(test_img, cartoon, or_img);						// 图片或运算:只有0||0为假,其余为真(0||1,1||1)
    	cv::bitwise_xor(test_img, cartoon, xor_img);					// 图片异或运算:相同为假,不同为真
    
    	cv::imshow("Weight_img", Weight_img);
    	cv::imshow("not_img", not_img);
    	cv::imshow("and_img", and_img);
    	cv::imshow("or_img", or_img);
    	cv::imshow("xor_img", xor_img);
    
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

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

    图像更改

    缩小放大 cv::resize

    void resize( InputArray src, OutputArray dst, Size dsize, double fx = 0, double fy = 0,int interpolation = INTER_LINEAR );
    	/** 最近邻插值 */
        INTER_NEAREST        = 0,
        /** 双线性插值 */
        INTER_LINEAR         = 1,
        /** 双三次插值 */
        INTER_CUBIC          = 2,
        /** 利用像素面积关系重采样。它可能是图像抽取的首选方法,如它提供无云纹的结果。但是当图像被放大时,它类似于INTER_NEAREST方法 */
        INTER_AREA           = 3,
        /** 8x8邻域上的Lanczos插值 */
        INTER_LANCZOS4       = 4,
        /** 位精确双线性插值 */
        INTER_LINEAR_EXACT = 5,
        /** 位精确最近邻插值。这将产生相同的结果在PIL, scikit-image或Matlab中的最近邻方法 */
        INTER_NEAREST_EXACT  = 6,
        /** 插值码掩码 */
        INTER_MAX            = 7,
        /** 标志,填充所有目标图像像素。如果它们中的一些对应于异常值源图像,它们被设为零 */
        WARP_FILL_OUTLIERS   = 8,
        /** 标志, 逆变换
    
        For example, #linearPolar or #logPolar transforms:
        - flag is __not__ set: \f$dst( \rho , \phi ) = src(x,y)\f$
        - flag is set: \f$dst(x,y) = src( \rho , \phi )\f$
        */
        WARP_INVERSE_MAP     = 16
    
    • 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

    翻转 cv::flip

    void flip(InputArray src, OutputArray dst, int flipCode);
    	//ROTATE_90_CLOCKWISE = 0, //!<顺时针旋转90度
        //ROTATE_180 = 1, //!<顺时针旋转180度
        //ROTATE_90_COUNTERCLOCKWISE = 2, //!<顺时针旋转270度
    
    • 1
    • 2
    • 3
    • 4

    旋转 cv::rotate

    	void rotate(InputArray src, OutputArray dst, int rotateCode);
    	// 顺时针旋转90度 (rotateCode = ROTATE_90_CLOCKWISE).
    	// 顺时针旋转180度 (rotateCode = ROTATE_180).
    	// 顺时针旋转270度 (rotateCode = ROTATE_90_COUNTERCLOCKWISE).
    
    • 1
    • 2
    • 3
    • 4

    仿射变换 cv::warpAffine

    // 参数2x3的M为变换矩阵{{1,0,x移动的量},{1,0,y移动的量}}
    void warpAffine( InputArray src, OutputArray dst,
                     InputArray M, Size dsize,
                     int flags = INTER_LINEAR,
                     int borderMode = BORDER_CONSTANT,
                     const Scalar& borderValue = Scalar());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    平移

    	// 方式1 使用Numpcc定义变换矩阵在转换成Mat变换矩阵
    	nc::NdArray<float> transMat = { {1,0,100},{0,1,100}};
    	cv::Mat imgtrans = cv::Mat(transMat.toStlVector(), CV_32FC1).reshape(0, 2);		// reshape(通道数, 行数)
    	// 方式2 使用cv::Mat直接定义变换矩阵
    	//cv::Mat imgtrans = cv::Mat::zeros(2, 3, CV_32FC1);
    	//imgtrans.at(0, 0) = 1;
    	//imgtrans.at(0, 2) = 100; //水平平移量
    	//imgtrans.at(1, 1) = 1;
    	//imgtrans.at(1, 2) = 100; //竖直平移量
    	cv::warpAffine(cartoon, cartoon, imgtrans, cv::Size(cartoon.cols,cartoon.rows));
    	cv::imshow("orig", cartoon);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    旋转

    中心点旋转

    	// getRotationMatrix2D(中心点,角度,缩放比例)
    	cv::Mat imgtrans = cv::getRotationMatrix2D(cv::Point(cartoon.cols / 2, cartoon.rows / 2), 20, 0.7);
    	cv::warpAffine(cartoon, cartoon, imgtrans, cv::Size(cartoon.cols, cartoon.rows));
    	cv::imshow("orig", cartoon);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    三点旋转

    在这里插入图片描述

    	// 方式1 使用Numpcc定义点集数组,再转换成Mat点集,再通过cv::getAffineTransform转换成变换矩阵
    	/*nc::NdArray srcPointArray = { {100,100},{300,100},{100,300} };
    	nc::NdArray dstPointArray = { {100,100},{300,300},{100,300} };
    	cv::Mat stcPointSet = cv::Mat(srcPointArray.toStlVector(), CV_32FC1).reshape(0, 3);		// reshape(通道数, 行数)
    	cv::Mat dstPointSet = cv::Mat(dstPointArray.toStlVector(), CV_32FC1).reshape(0, 3);*/
    	// 方式2 使用cv::Point2f直接定义点集,再通过cv::getAffineTransform转换成变换矩阵
    	cv::Point2f stcPointSet[] = { {100,100},{300,100},{100,300} };
    	cv::Point2f dstPointSet[] = { {100,100},{300,300},{100,300} };
    	cv::Mat imgtrans = cv::getAffineTransform(stcPointSet, dstPointSet);
    	cv::warpAffine(cartoon, cartoon, imgtrans, cv::Size(cartoon.cols, cartoon.rows));
    	cv::imshow("orig", cartoon);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    透视变换 cv::getPerspectiveTransform

    需要四个坐标点,用法和三点旋转差不多

    Mat getPerspectiveTransform(InputArray src, InputArray dst, int solveMethod = DECOMP_LU);
    
    • 1

    图像卷积

    卷积核:卷积核一般为奇数,如3x3,5x5,7x7等;一方面是增加padding的原因,另一方面是保证锚点在中间,防止位置发生偏移的原因。在深度学习中,卷积核越大看到的信息(感受野)越多提取的特征越好同时计算量也就越大。
    锚:主要作用是防止信息偏差
    边界扩充(padding):当卷积核大于1且不进行边界扩充,输出尺寸将相应缩小。当卷积核以标准方式进行边界扩充,则输出数据的空间尺寸将与输入相等。
    在这里插入图片描述

    滤波:对目标图像的噪声进行抑制
    输出图像大小的计算公式:

    dst = (src-kernel+2P)/S+1
    src:输入图像的大小
    dst :输出图像的大小
    kernel:卷积核的大小
    P:扩充边界的数量
    S:步长
    例子:输入一个5x5的图像,卷积核为3x3,没有扩充边界,步长为2。 (5-3+2*0)/ 2 + 1 = 2 ,所以输出图像大小为2x2

    滤波(卷积核)

    低通滤波

    低通滤波可以去除噪声或平滑图像

    方盒滤波和均值滤波

    方盒滤波和均值滤波得到的效果相同,其原理是将卷积核均化,即卷积核除以(卷积核的长x宽)得到一个新的卷积核

    //方盒滤波
    void boxFilter( InputArray src, OutputArray dst, int ddepth,
                                 Size ksize, Point anchor = Point(-1,-1),
                                 bool normalize = true,
                                 int borderType = BORDER_DEFAULT );
    //均值滤波
    void blur( InputArray src, OutputArray dst,
                            Size ksize, Point anchor = Point(-1,-1),
                            int borderType = BORDER_DEFAULT );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    	cv::Mat dst_boxFilter, dst_blur;
    	// 自定义卷积核
    	//cv::filter2D(cartoon, dst, -1, kernel);
    	// 方盒滤波
    	cv::boxFilter(cartoon, dst_boxFilter, -1, cv::Size(5, 5));
    	// 均值滤波
    	cv::blur(cartoon, dst_blur, cv::Size(5, 5));
    
    	cv::imshow("dst_boxFilter", dst_boxFilter);
    	cv::imshow("dst_blur", dst_blur);
    	cv::imshow("cartoon", cartoon);
    
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    高斯滤波

    原理是越往卷积核中心的比重越大
    在这里插入图片描述

    GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                                    double sigmaX, double sigmaY = 0,
                                    int borderType = BORDER_DEFAULT );
    
    • 1
    • 2
    • 3
    cv::Mat dst_GaussianBlur_x3, dst_GaussianBlur_x1, dst_GaussianBlur_x01;
    	// 高斯滤波 GaussianBlur(原图,输出图,核大小,x方向的标准差,y方向的标准差)
    	cv::GaussianBlur(cartoon, dst_GaussianBlur_x3, cv::Size(5, 5), 3);
    	cv::GaussianBlur(cartoon, dst_GaussianBlur_x01, cv::Size(5, 5), 0.1);
    	cv::GaussianBlur(cartoon, dst_GaussianBlur_x1, cv::Size(5, 5), 1);
    	
    	cv::imshow("cartoon", cartoon);
    	cv::imshow("dst_GaussianBlur_x3", dst_GaussianBlur_x3);
    	cv::imshow("dst_GaussianBlur_x01", dst_GaussianBlur_x01);
    	cv::imshow("dst_GaussianBlur_x1", dst_GaussianBlur_x1);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    中值滤波

    原理是将核排序后取中值作为核的新元素
    优点:对胡椒噪效果明显

    void medianBlur( InputArray src, OutputArray dst, int ksize );
    
    • 1
    cv::Mat dst_medianBlur
    	// 中值滤波
    	cv::medianBlur(cartoon, dst_medianBlur, 15);
    	cv::imshow("cartoon", cartoon);
    	cv::imshow("dst_medianBlur", dst_medianBlur);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    双边滤波

    原理:
    在这里插入图片描述

    优点:可以保留边缘,同时对边缘内的图像进行平滑处理。如:美颜

    
    CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
                                       double sigmaColor, double sigmaSpace,
                                       int borderType = BORDER_DEFAULT );
    /*	@param src 源8位或浮点,1通道或3通道图像.
    	@param dst 目标图像的大小和类型与src相同.
    	@param d 在滤波过程中使用的每个像素邻域的直径。如果它是非正的,它是从sigmaSpace计算的。
    	@param sigmaColor 在颜色空间中过滤。该参数的较大值意味着更远的颜色与像素附近的(参见sigmasspace)将混合在一起,形成大面积的半对等色。
    	@param sigmaSpace 在坐标空间中过滤。该参数的较大值意味着更远的像素会相互影响,只要它们的颜色足够接近(参见igmaColor)
    )。当d>0时,它指定邻域大小,而不考虑sigmasspace。否则,d是
    与sigmaSpace成正比。
    	@param borderType 用于推断图像外部像素的边界模式
     */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    	// 双边滤波
    	cv::bilateralFilter(person, dst_bilateralFilter, -1, 50, 40);
    	cv::imshow("person", person);
    	cv::imshow("dst_bilateralFilter", dst_bilateralFilter);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    高通滤波

    高通滤波可以帮助查找图像的边缘

    Sobel

    原理:在内部通过高斯滤波对噪音进行过滤,再通过一阶导求得图像边缘。
    优点:抗噪声强
    缺点:需要对横轴和纵轴分别计算,再合并结果
    Sobel算子(Sobel卷积核):先向X方向求导,再向y方向求导,将两个结果相加

    void Sobel( InputArray src, OutputArray dst, int ddepth,
                             int dx, int dy, int ksize = 3,
                             double scale = 1, double delta = 0,
                             int borderType = BORDER_DEFAULT );
    /*@param ddepth 输出图像深度,见@ref filter_depth " composites ";在8位输入图像的情况下,它将导致截断导数。
    @param dx x的导数的阶。
    @param dy y的导数的阶。
    @param ksize 扩展Sobel核的大小;它一定是1 3 5 7, 设为-1时变成Scharr算子
    @param scale 计算出的导数值的可选比例因子;默认情况下,不应用缩放(详见# getderikernels)。
    @param delta 可选的增量值,在将结果存储到dst之前添加到结果中。
    @param borderType 像素外推方法,参见#BorderTypes。#BORDER_WRAP不支持。@sa  Scharr, Laplacian, sepFilter2D, filter2D, GaussianBlur, cartToPolar
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    	// sobel算子
    	cv::Mat dst_sobel_x, dst_sobel_y, dst_sobel;
    	cv::Sobel(cartoon, dst_sobel_y, -1, 1, 0);		// 获取y方向的边缘
    	cv::Sobel(cartoon, dst_sobel_x, -1, 0, 1);		// 获取x方向的边缘
    	cv::add(dst_sobel_x, dst_sobel_y, dst_sobel);
    	
    	cv::imshow("cartoon", cartoon);
    	cv::imshow("dst_sobel", dst_sobel);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    Scharr

    卷积核固定为3x3
    优点:线条清晰
    缺点:需要对横轴和纵轴分别计算,再合并结果。

    	// 将Sobel算子的核大小设为-1时,就形成了scharr算子
    	cv::Sobel(cartoon, dst_sobel_y, -1, 1, 0,-1);		// 获取y方向的边缘
    	cv::Sobel(cartoon, dst_sobel_x, -1, 0, 1,-1);		// 获取x方向的边缘
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    Laplacian

    优点:不需要对横轴和纵轴分别计算,直接获取处理后的图片。
    缺点:噪声敏感,需要手工降噪

    void Laplacian( InputArray src, OutputArray dst, int ddepth,
                                 int ksize = 1, double scale = 1, double delta = 0,
                                 int borderType = BORDER_DEFAULT );
    
    • 1
    • 2
    • 3
    	// Laplacian 算子
    	cv::Mat dst_Laplacian;
    	cv::Laplacian(cartoon, dst_Laplacian, -1, 3);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    快捷小技巧

    指定位置更改颜色 cv::Mat().setTo

    	cv::Mat background = cv::Mat(cv::Size(200, 200), CV_8UC3);
    	background.setTo(cv::Scalar(255,255,255));
    	background({ 10,110 }, { 20,130 }).setTo(cv::Scalar(0, 255, 255));
    	background({ 80,190 }, { 70,180 }).setTo(cv::Scalar(0, 255, 255));
    	cv::imshow("background", background);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    指定位置加入图片 cv::Mat().copyTo

    	cv::resize(cartoon_gry, logo_img, { 65,150 });	//重新设置图片大小
    	// 1.ROI方法
    	//cv::Rect temp = cv::Rect(10, 20,   logo_img.size().width, logo_img.size().height);
    	//logo_img.copyTo(cartoon_gry(temp));
    	//2.直接指定具体范围
    	logo_img.copyTo(cartoon_gry({ 10,10+ logo_img.size().height }, { 20,20+ logo_img.size().width }));
    	cv::imshow("cartoon_gry", cartoon_gry);
    	cv::waitKey(0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

  • 相关阅读:
    生成型神经网络
    【小沐学QT】QT学习之Web控件的使用
    一汽大众迈腾车前悬架系统设计
    【华为OD机试高分必刷题目】神奇的卡片(Java-等差数列实现)
    [附源码]SSM计算机毕业设计疫情防控期间人员档案追寻系统JAVA
    【牛客网-公司真题-前端入门篇】——如何快速上手牛客
    【操作系统】页表映射
    Spring4 + SpringMVC + Hibernate4 环境搭建
    分布式数据库选型之争:数据库向左,中间件向右
    JDBC(Java数据库连接)
  • 原文地址:https://blog.csdn.net/Vone_66/article/details/127642497