问题引出

要做的是,不要提取到树叶和树枝,只是把荔枝(果实)的轮廓提取出来
思路
1.首先将RGB图像转成HSV图像
2.在HSV下,将色温为红色的标白,其他颜色的标黑.
3.然后根据这个图,双重for循环,检测周围的点,如果是01分界就打点,否则继续遍历下一个点。
转化为HSV图像并且完成标记
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <cstring>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("E:/data/h3.jpg", IMREAD_UNCHANGED);
//创建hsv图像
Mat hsv, gray;
if (src.empty())
{
cout << "ERROR!";
return 0;
}
cvtColor(src, hsv,COLOR_BGR2HSV);
//imshow("hsv", hsv);
//创建灰度图像
gray = Mat::zeros(src.size(), src.type());
cv::cvtColor(gray, gray, COLOR_BGR2GRAY);
imshow("gray", gray);
//遍历HSV图像,并且得到正确的区域。
int width = src.cols;
int height = src.rows;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
std::vector <int> colorVec;
colorVec.push_back(hsv.at<Vec3b>(i, j)[0]);
colorVec.push_back(hsv.at<Vec3b>(i, j)[1]);
colorVec.push_back(hsv.at<Vec3b>(i, j)[2]);
//存储三个通道的数据,然后进行颜色的判别.
if (((colorVec[0] >= 156 && colorVec[0] <= 180)|| (colorVec[0] >= 0 && colorVec[0]<=10) )&& (colorVec[1] >= 43 && colorVec[1] <= 255) && (colorVec[2] >= 46 && colorVec[2] <= 255))
{
gray.at<uchar>(i, j) =255;//红色的就设置成255
}
}
}
imshow("gray2", gray);
waitKey(0);
destroyAllWindows();
return 0;
}

提取到这一步,只是有了一个基本的轮廓,那么该如何处理呢,我们看到图像内还是有很多孤立的点,甚至树枝都还存在,那么这时候就需要调阈值了。
微调阈值
微调的思路是首先一个个排除通道,根据表格来看,选取比较合适的HSV值.

这是微调阈值后的图片,三个阈值对分别为:
(118,180)(0,18)、(26,255)、(28,255)
对图像进行平滑处理
//图像的平滑处理,尽可能把那些孤立的点给去掉
Mat res = Mat::zeros(src.size(), src.type());
GaussianBlur(gray, res, Size(3, 3), 5);
Canny(res, res, 100, 300, 3);
imshow("gussin", res);
接下来就是一些孤立的区域的去除,考虑采用的是高斯滤波,尽量平滑。
以下给出完整程序,关键总结:
①HSV阈值调整,尽可能去除孤立点,使得图像完整
②高斯滤波+Canny高阈值边缘检测组合去除小孤立区域
完整代码:
#include <opencv2/opencv.hpp>
#include <cstring>
#include <vector>
#include <cstdio>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("E:/data/h3src.jpg", IMREAD_UNCHANGED);//输入图像的入口
//创建hsv图像
imshow("src", src);
Mat hsv, gray;
if (src.empty())
{
cout << "ERROR!";
return 0;
}
cvtColor(src, hsv, COLOR_BGR2HSV);
//imwrite("E:/data/h3hsv.jpg", hsv);
//imshow("src", src);
//创建灰度图像
gray = Mat::zeros(src.size(), src.type());
cv::cvtColor(gray, gray, COLOR_BGR2GRAY);
//imshow("gray", gray);
//Mat cmp = imread("E:/outputdata/gray2.jpg");
//imshow("src", cmp);
//遍历HSV图像,并且得到正确的区域。
int width = src.cols;
int height = src.rows;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
std::vector <int> colorVec;
colorVec.push_back(hsv.at<Vec3b>(i, j)[0]);
colorVec.push_back(hsv.at<Vec3b>(i, j)[1]);
colorVec.push_back(hsv.at<Vec3b>(i, j)[2]);
//存储三个通道的数据,然后进行颜色的判别.
if ((((colorVec[0] >= 118 && colorVec[0] <= 180) || (colorVec[0] >= 0 && colorVec[0] <= 18))) && (colorVec[1] >= 26 && colorVec[1] <= 255) && (colorVec[2] >= 28 && colorVec[2] <= 255))
{
gray.at<uchar>(i, j) = 255;//红色的就设置成255
}
}
}
//imshow("gray2", gray);
//图像的平滑处理
Mat res = Mat::zeros(src.size(), src.type());
GaussianBlur(gray, res, Size(9, 9), 5);
Canny(res, res, 100, 300, 3);
imshow("gussin", res);
//此时的轮廓已经提取得差不多了,然后就是要做一个去除孤立点操作
for (int i = 0; i < res.rows; i++)
{
for (int j = 0; j < res.cols; j++)
{
if (res.at<uchar>(i, j) == 0)
{
res.at<uchar>(i, j) = 255;
continue;
}
res.at<uchar>(i, j) = 0;
}
}
imshow("res", res);
imwrite("E:/data-output/h3res.jpg",res);
//图像中还有一些细小的点,实在不知道怎么处理了。。
waitKey(0);
destroyAllWindows();
return 0;
}

这篇博客介绍了如何通过HSV颜色空间转换和Canny边缘检测算法,精确地从图像中提取荔枝果实的轮廓。作者首先将RGB图像转换为HSV图像,设定红色区域的阈值来标记果实,然后通过高斯滤波和Canny边缘检测去除孤立点和树枝,最终得到较为完整的荔枝轮廓。
实战案例3:提取在复杂环境下的特定目标轮廓&spm=1001.2101.3001.5002&articleId=119914768&d=1&t=3&u=0600899dd8744185bcc98b1beba2d8c1)
2090

被折叠的 条评论
为什么被折叠?



