Bootstrap

9.3 opencv对图片的分割处理(c++)

        首先我们根据博客9.2 c++搭建opencv环境-CSDN博客搭建opencv环境,然后对图片进行处理,在这里,对图片的分割没有用opencv里的函数,而是根据自己的理解用循环和做差写的函数,分割的效果和opencv的相似。

用visua studio建立的文件路径如下:

1.建立 imgchuli2.cpp 文件,该文件用来写处理图片的函数

        以下代码的具体原理和解释可以看博客2 图片的分割处理和亚像素精度处理(c++和python)_亚像素处理-CSDN博客

        函数代码如下:

// OpencvPractice.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include<opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include<list>
#include<vector>
#include <typeinfo>


using namespace cv;
using namespace std;

#define KERNEL_SUM 8


int mainss2()
{ 
    static Mat kernels[KERNEL_SUM];

    if (kernels[0].empty())
    {
        int k = 0;
        kernels[k++] = (Mat_<float>(3, 3) << 1, 2, 1, 0, 0, 0, -1, -2, -1);	// 270°
        kernels[k++] = (Mat_<float>(3, 3) << 2, 1, 0, 1, 0, -1, 0, -1, -2);	// 315°
        kernels[k++] = (Mat_<float>(3, 3) << 1, 0, -1, 2, 0, -2, 1, 0, -1);	// 0°
        kernels[k++] = (Mat_<float>(3, 3) << 0, -1, -2, 1, 0, -1, 2, 1, 0);	// 45°

        flip(kernels[0], kernels[k++], 0);											// 90°

        kernels[k++] = (Mat_<float>(3, 3) << -2, -1, 0, -1, 0, 1, 0, 1, 2);	// 135°

        flip(kernels[2], kernels[k++], 1);											// 180°

        kernels[k++] = (Mat_<float>(3, 3) << 0, 1, 2, -1, 0, 1, -2, -1, 0);	// 225°
    }

    // 梯度图像
    Mat gradients[KERNEL_SUM];
    // 检测图像, 路径自己更改, 注意要是单通道图像
    Mat imgsrc = imread("E:\\vs\\daima\\opencvs\\OpencvPractice\\4.jpg");//IMREAD_ANYCOLOR

    for (int k = 0; k < KERNEL_SUM; k++)
    {
        filter2D(imgsrc, gradients[k], CV_16S, kernels[k]);// CV_64F    //

        Mat imgshowt;
        normalize(gradients[k], imgshowt, 0, 255, NORM_MINMAX);
        cv::Mat rlt;
        imgshowt.convertTo(rlt, CV_8UC1);//将imgshowt转换为无符号单通道的整型并赋值给rlt  CV_8UC1
        //
        cvtColor(rlt, gradients[k], cv::COLOR_BGR2GRAY);//将rlt转换为灰度图并赋值给gradients[k]
        
        //imshow("img", rlt);
        //waitKey(0);
    }



    //2. 梯度方向
      // (1. 角度列表
    const short angle_list[] = { 270, 315, 0, 45, 90, 135, 180, 225 };
    // (2. 总幅值矩阵
    Mat amplitude(imgsrc.rows, imgsrc.cols, CV_8UC1, Scalar::all(0));

    // (3. 角度矩阵, 后面初始化成 -64 只是为了归一化之后能显示角度 0
    Mat angle(imgsrc.rows, imgsrc.cols, CV_16SC1, Scalar::all(-64));//CV_16SC1   -64

    for (int r = 0; r < imgsrc.rows; r++)
    {

        short* pAng = angle.ptr<short>(r);//short

 

        for (int c = 0; c < imgsrc.cols; c++)
        {
            // 找出最大值
            for (int i = 0; i < KERNEL_SUM; i++)
            {
                if (amplitude.ptr<unsigned char>(r)[c] < gradients[i].ptr<unsigned char>(r)[c])
                {
                    amplitude.ptr<unsigned char>(r)[c] = gradients[i].ptr<unsigned char>(r)[c];
                    pAng[c] = angle_list[i];
                }
            }
            
        }
    }
    

    Mat imgshow;

    imshow("amplitude", amplitude);
    //imwrite("D:\Datas\\1.jpg",amplitude);
    waitKey(0);

    normalize(angle, imgshow, 0, 255, NORM_MINMAX);
    imgshow.convertTo(imgshow, CV_8UC1);
    imshow("amplitude", imgshow);
    waitKey(0);

    // 3.单像素边缘,整数坐标边缘图像
    //cout << "===============> start 单像素边缘 <================" << endl;
    
    
    // 阈值
    double thres = 158;	// 此处为增加
    Mat edge(imgsrc.rows, imgsrc.cols, CV_8UC1, Scalar::all(0));

    for (int r = 1; r < imgsrc.rows - 1; r++)
    {
        // 3 * 3 邻域, 所以用 3 个指针, 一个指针指一行
        const unsigned char* pAmp1 = amplitude.ptr<unsigned char>(r - 1);
        const unsigned char* pAmp2 = amplitude.ptr<unsigned char>(r);
        const unsigned char* pAmp3 = amplitude.ptr<unsigned char>(r + 1);

        const short* pAng = angle.ptr<short>(r);
        unsigned char* pEdge = edge.ptr<unsigned char>(r);

        for (int c = 1; c < imgsrc.cols - 1; c++)
        {

            // 以下判断为增加部分
            if (pAmp2[c] < thres)
            {
                continue;
            }
            //

            switch (pAng[c])
            {
            case 270:
                if (pAmp2[c] > pAmp1[c] && pAmp2[c] >= pAmp3[c])
                {
                    pEdge[c] = 255;
                }
                break;
            case 90:
                if (pAmp2[c] >= pAmp1[c] && pAmp2[c] > pAmp3[c])
                {
                    pEdge[c] = 255;
                }
                break;

            case 315:
                if (pAmp2[c] > pAmp1[c - 1] && pAmp2[c] >= pAmp3[c + 1])
                {
                    pEdge[c] = 255;
                }
                break;
            case 135:
                if (pAmp2[c] >= pAmp1[c - 1] && pAmp2[c] > pAmp3[c + 1])
                {
                    pEdge[c] = 255;
                }
                break;

            case 0:
                if (pAmp2[c] > pAmp2[c - 1] && pAmp2[c] >= pAmp2[c + 1])
                {
                    pEdge[c] = 255;
                }
                break;
            case 180:
                if (pAmp2[c] >= pAmp2[c - 1] && pAmp2[c] > pAmp2[c + 1])
                {
                    pEdge[c] = 255;
                }
                break;

            case 45:
                if (pAmp2[c] >= pAmp1[c + 1] && pAmp2[c] > pAmp3[c - 1])
                {
                    pEdge[c] = 255;
                }
                break;
            case 225:
                if (pAmp2[c] > pAmp1[c + 1] && pAmp2[c] >= pAmp3[c - 1])
                {
                    pEdge[c] = 255;
                }
                break;

            default:
                break;
            }
        }
    }
    imshow("edg", edge);//总共有462个点为255(白色)
    imwrite("D:\Datas\\2.jpg", edge);
    waitKey(0);

    //cout << "===============> end 单像素边缘 <================" << endl;

    // 4. 亚像素坐标
    cout << "===============> start 亚像素坐标 <================" << endl;

    // 根号2
    const double root2 = sqrt(2.0);
    // 三角函数表
    double tri_list[2][KERNEL_SUM] = { 0 };

    for (int i = 0; i < KERNEL_SUM; i++)
    {
        tri_list[0][i] = cos(angle_list[i] * CV_PI / 180.0);
        // sin前面的负号非常关键, 因为图像的y方向和直角坐标系的y方向相反
        tri_list[1][i] = -sin(angle_list[i] * CV_PI / 180.0);
    }

    // vector 方式记录小数坐标
    vector<Point3f> vPts;
    // Mat 方式记录小数坐标, 注意这里是双通道
    Mat coordinate(imgsrc.rows, imgsrc.cols, CV_32FC2, Scalar::all(0));

    for (int r = 1; r < imgsrc.rows - 1; r++)
    {
        // 3 * 3 邻域, 所以用3个指针, 一个指针指一行
        const short* pAmp1 = amplitude.ptr<short>(r - 1);
        const short* pAmp2 = amplitude.ptr<short>(r);
        const short* pAmp3 = amplitude.ptr<short>(r + 1);

        const short* pAng = angle.ptr<short>(r);
        const short* pEdge = edge.ptr<short>(r);

        float* pCoordinate = coordinate.ptr<float>(r);

        for (int c = 1; c < imgsrc.cols - 1; c++)
        {
            if (pEdge[c])
            {
                int nAngTmp = 0;
                double dTmp = 0;

                switch (pAng[c])
                {
                case 270:
                    nAngTmp = 0;
                    dTmp = ((double)pAmp1[c] - pAmp3[c]) / (pAmp1[c] + pAmp3[c] - 2 * pAmp2[c] + 0.000001) * 0.5;
                    break;

                case 90:
                    nAngTmp = 4;
                    dTmp = -((double)pAmp1[c] - pAmp3[c]) / (pAmp1[c] + pAmp3[c] - 2 * pAmp2[c] + 0.000001) * 0.5;
                    break;

                case 315:
                    nAngTmp = 1;
                    dTmp = ((double)pAmp1[c - 1] - pAmp3[c + 1]) / (pAmp1[c - 1] + pAmp3[c + 1] - 2 * pAmp2[c] + 0.000001) * root2 * 0.5;
                    break;

                case 135:
                    nAngTmp = 5;
                    dTmp = -((double)pAmp1[c - 1] - pAmp3[c + 1]) / (pAmp1[c - 1] + pAmp3[c + 1] - 2 * pAmp2[c] + 0.000001) * root2 * 0.5;
                    break;

                case 0:
                    nAngTmp = 2;
                    dTmp = ((double)pAmp2[c - 1] - pAmp2[c + 1]) / (pAmp2[c - 1] + pAmp2[c + 1] - 2 * pAmp2[c] + 0.000001) * 0.5;
                    break;

                case 180:
                    nAngTmp = 6;
                    dTmp = -((double)pAmp2[c - 1] - pAmp2[c + 1]) / (pAmp2[c - 1] + pAmp2[c + 1] - 2 * pAmp2[c] + 0.000001) * 0.5;
                    break;

                case 45:
                    nAngTmp = 3;
                    dTmp = ((double)pAmp3[c - 1] - pAmp1[c + 1]) / (pAmp1[c + 1] + pAmp3[c - 1] - 2 * pAmp2[c] + 0.000001) * root2 * 0.5;
                    break;

                case 225:
                    nAngTmp = 7;
                    dTmp = -((double)pAmp3[c - 1] - pAmp1[c + 1]) / (pAmp1[c + 1] + pAmp3[c - 1] - 2 * pAmp2[c] + 0.000001) * root2 * 0.5;
                    break;

                default:
                    break;
                }

                const double x = c + dTmp * tri_list[0][nAngTmp];
                const double y = r + dTmp * tri_list[1][nAngTmp];
                const short z = angle_list[nAngTmp];

                // vector方式
                vPts.push_back(Point3f((float)x, (float)y, (short)z));

                // Mat 方式
                pCoordinate[c << 1] = (float)x;
                pCoordinate[(c << 1) + 1] = (float)y;
            }
        }
    }

    //cout << "" << vPts.size() << endl;//总共有462个点为255(白色)
    //for (size_t i = 0; i < vPts.size(); i++)
    //{
    //    cout << vPts[i].z << ":    " << vPts[i].x << ",    " << vPts[i].y <<endl;
    //}

    cout << "===============> end 亚像素坐标 <================" << endl;
    return 0;

}

以上代码已经做了具体的注释,在这里不多做赘述。

2.建立 imgchuli2.h 文件

代码如下:

int mainss2();

3.建立OpencvPractice.cpp函数

代码如下:

#include<iostream>
#include "imgschuli.h"//mainss();
#include "Polynomial.h" //mains();
#include "imgchuli2.h"//mainss2();
#include "imgchuli3.h"//mainss3();
#include "listss.h"//mainss3();

using namespace std;
//using namespace cv;


int main()
{
	cout << "===============> start <================" << endl;
	cout << endl;
	//.........................start...........................
	//1.读取Mat类的元素
	//mainss();

	//2. 创建不同的3x3的卷积核,并对图片进行 filter2D 处理,显示不同卷积核处理后的效果
	mainss2();
	

	//2. 创建不同的3x3的卷积核,并对图片进行 filter2D 处理,快速版显示不同卷积核处理后的效果
	//mainss3();
	lists();

	//.........................end.............................
	cout << endl;
	cout << "===============> end <================" << endl;

	int ss = 8;
	int r = ss % 5;
	cout << r << endl;

	return 0;
}

4.图片的处理结果

原图片:

处理一:

处理二:

处理三:

;