问题引出
要做的是,不要提取到树叶和树枝,只是把荔枝(果实)的轮廓提取出来
思路
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);
Mat hsv, gray;
if (src.empty())
{
cout << "ERROR!";
return 0;
}
cvtColor(src, hsv,COLOR_BGR2HSV);
gray = Mat::zeros(src.size(), src.type());
cv::cvtColor(gray, gray, COLOR_BGR2GRAY);
imshow("gray", gray);
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;
}
}
}
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);
imshow("src", src);
Mat hsv, gray;
if (src.empty())
{
cout << "ERROR!";
return 0;
}
cvtColor(src, hsv, COLOR_BGR2HSV);
gray = Mat::zeros(src.size(), src.type());
cv::cvtColor(gray, gray, COLOR_BGR2GRAY);
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;
}
}
}
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;
}
|