欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 游戏 > 9.3 opencv对图片的分割处理(c++)

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

2025/9/14 14:54:15 来源:https://blog.csdn.net/weixin_71719718/article/details/145007400  浏览:    关键词: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 8int 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_ANYCOLORfor (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 只是为了归一化之后能显示角度 0Mat angle(imgsrc.rows, imgsrc.cols, CV_16SC1, Scalar::all(-64));//CV_16SC1   -64for (int r = 0; r < imgsrc.rows; r++){short* pAng = angle.ptr<short>(r);//shortfor (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;// 根号2const 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.图片的处理结果

原图片:

处理一:

处理二:

处理三:

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com