原图:
1. RGB转化为HSV
cvtColor(srcImage, hsv, CV_BGR2HSV);
2. 得到红色区域掩膜
//设置HSV色彩空间各个分量的范围,Hue:色调,Saturation:饱和度,Value:明度
double low_H = 0; //156
double low_S = 43;
double low_V = 46;
double high_H = 10; //180
double high_S = 255;
double high_V = 255;
//使用inrange函数,将在这个范围的颜色提取出来,得到mask矩阵
cv::inRange(hsv, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), mask);
hsv色彩空间颜色范围:
3. 对掩膜进行膨胀与腐蚀操作
//得到结构元素(内核矩阵),MORPH_RECT表示内核形状为矩形,Size(30, 30)表示内核的尺寸
Mat kernel = getStructuringElement(MORPH_RECT, Size(30, 30));
//对掩码进行膨胀,MORPH_DILATE表示进行膨胀操作
morphologyEx(mask, mask, MORPH_DILATE, kernel);
//对掩膜进行腐蚀,MORPH_ERODE表示进行腐蚀操作
morphologyEx(mask, mask, MORPH_ERODE, kernel);
膨胀:
腐蚀:
4. 分割图像
Mat divmask = mask;
divmask = divmask / 255;
Mat channels[3];
//分离色彩通道
split(srcImage, channels);
//分别乘以1或0
channels[0] = channels[0].mul(mask);
channels[1] = channels[1].mul(mask);
channels[2] = channels[2].mul(mask);
//将背景区域填成白色
for (int i = 0; i<channels[0].rows; i++)
{
for (int j = 0; j<channels[0].cols; j++)
{
if ((channels[0].at<int8_t >(i, j) == 0) && (channels[1].at<int8_t >(i, j) == 0) && (channels[2].at<int8_t >(i, j) == 0))
{
channels[0].at<int8_t >(i, j) = 255;
channels[1].at<int8_t >(i, j) = 255;
channels[2].at<int8_t >(i, j) = 255;
}
}
}
Mat divImage;
//合成RGB
merge(channels, 3, divImage);
5. 寻找轮廓
//向量contours内每个元素保存了一组由连续的Point点构成的点的集合的向量,在这里用来保存轮廓
vector<vector<Point> > contours;
//findContours用于寻找轮廓,单通道二值图
//RETR_EXTERNAL表示只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
//CHAIN_APPROX_NONE表示保存物体边界上所有连续的轮廓点到contours向量;CHAIN_APPROX_SIMPLE表示仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量
findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
//绘制轮廓,第3个参数代表contours向量的下标,为0表示绘制第一个轮廓;最后一个参数-1代表绘制时填充轮廓,若大于0则指轮廓厚度
drawContours(srcImage, contours, 0, Scalar(255, 0, 0), 3);
6. 得到最小面积矩形 ,该矩形与图像边界不平行
//minAreaRect函数用于求点集最小面积的矩形,这个矩形是可以有偏转角度的,即可以与图像的边界不平行
//RotatedRect是一个存储旋转矩形的类,minAreaRect函数返回的最小面积矩形存储在rect对象中
RotatedRect rect = minAreaRect(contours[0]);
Point2f vertices[4];
//得到矩形的4个顶点
rect.points(vertices);
for (int i = 0; i < 4; i++)
line(srcImage, vertices[i], vertices[(i + 1) % 4], Scalar(0, 255, 0));
7. 得到包含旋转矩形的最小矩形 ,该矩形与边界平行
//得到包含旋转矩形的最小矩形
Rect brect = rect.boundingRect();
rectangle(srcImage, brect, Scalar(0, 0, 255));
8. 裁剪
imwrite("9_裁剪.jpg", srcImage(brect));
9. 完整代码
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace std;
//根据面积对轮廓进行排序所需要的用于比较的函数
bool ContoursSortFun(vector<cv::Point> contour1, vector<cv::Point> contour2){
return (cv::contourArea(contour1) > cv::contourArea(contour2));
}
int main()
{
Mat srcImage;
Mat hsv;
Mat mask;
//加载图像
srcImage = imread("src.jpg");
if (srcImage.empty()) {
cout << "could not load image..." << endl;
return -1;
}
else cout << "load succsessful." << endl;
//imshow("原图src", srcImage);
//转化为 hsv
cvtColor(srcImage, hsv, CV_BGR2HSV);
//imshow("1_hsv", hsv);
imwrite("1_hsv.jpg", hsv);
//设置HSV色彩空间各个分量的范围,Hue:色调,Saturation:饱和度,Value:明度
double low_H = 0; //156
double low_S = 43;
double low_V = 46;
double high_H = 10; //180
double high_S = 255;
double high_V = 255;
//使用inrange函数,将在这个范围的颜色提取出来,得到mask矩阵
inRange(hsv, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), mask);
//imshow("2_mask", mask);
imwrite("2_mask.jpg", mask);
//得到结构元素(内核矩阵),MORPH_RECT表示内核形状为矩形,Size(30, 30)表示内核的尺寸
Mat kernel = getStructuringElement(MORPH_RECT, Size(30, 30));
//对掩码进行膨胀,MORPH_DILATE表示进行膨胀操作
morphologyEx(mask, mask, MORPH_DILATE, kernel);
//imshow("3_mask_dilate", mask);
imwrite("3_mask_dilate.jpg", mask);
//对掩膜进行腐蚀,MORPH_ERODE表示进行腐蚀操作
morphologyEx(mask, mask, MORPH_ERODE, kernel);
//imshow("3_mask_erode", mask);
imwrite("3_mask_erode.jpg", mask);
Mat divmask = mask;
divmask = divmask / 255;
Mat channels[3];
//分离色彩通道
split(srcImage, channels);
//分别乘以1或0
channels[0] = channels[0].mul(mask);
channels[1] = channels[1].mul(mask);
channels[2] = channels[2].mul(mask);
//将背景区域填成白色
for (int i = 0; i<channels[0].rows; i++){
for (int j = 0; j<channels[0].cols; j++){
if ((channels[0].at<int8_t >(i, j) == 0) && (channels[1].at<int8_t >(i, j) == 0) && (channels[2].at<int8_t >(i, j) == 0)){
channels[0].at<int8_t >(i, j) = 255;
channels[1].at<int8_t >(i, j) = 255;
channels[2].at<int8_t >(i, j) = 255;
}
}
}
Mat divImage;
//合成RGB
merge(channels, 3, divImage);
//imshow("4_divImage", divImage);
imwrite("4_divImage.jpg", divImage);
//向量contours内每个元素保存了一组由连续的Point点构成的点的集合的向量,在这里用来保存轮廓
vector<vector<Point> > contours;
//findContours用于在单通道二值图中寻找轮廓
//RETR_EXTERNAL表示只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
//CHAIN_APPROX_NONE表示保存物体边界上所有连续的轮廓点到contours向量;CHAIN_APPROX_SIMPLE表示仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量
findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
//cout << contours.size();
//对所得到的轮廓按面积大小排序,由于只得到了最外侧的一个轮廓,因此不需要排序
//sort(contours.begin(), contours.end(), ContoursSortFun);
//绘制轮廓,第3个参数代表contours向量的下标,为0表示绘制第一个轮廓;最后一个参数-1代表绘制时填充轮廓,若大于0则指轮廓厚度
drawContours(srcImage, contours, 0, Scalar(255, 0, 0), 3);
imshow("5_绘制轮廓", srcImage);
imwrite("5_绘制轮廓.jpg", srcImage);
//minAreaRect函数用于求点集最小面积的矩形,这个矩形是可以有偏转角度的,即可以与图像的边界不平行
//RotatedRect是一个存储旋转矩形的类,minAreaRect函数返回的最小面积矩形存储在rect对象中
RotatedRect rect = minAreaRect(contours[0]);
Point2f vertices[4];
//得到矩形的4个顶点
rect.points(vertices);
for (int i = 0; i < 4; i++)
line(srcImage, vertices[i], vertices[(i + 1) % 4], Scalar(0, 255, 0));
//imshow("6_最小面积的矩形", srcImage);
imwrite("6_最小面积的矩形.jpg", srcImage);
//得到包含旋转矩形的最小矩形
Rect brect = rect.boundingRect();
rectangle(srcImage, brect, Scalar(0, 0, 255));
//imshow("7_最小矩形", srcImage);
imwrite("7_最小矩形.jpg", srcImage);
//imshow("8_裁剪", srcImage(brect));
imwrite("8_裁剪.jpg", srcImage(brect));
waitKey();
return 0;
}
若只要裁剪图片,则不需要进行图像分割,当然绘制轮廓也是不需要的,可自行根据需求修改。
参考:
使用Python和OpenCV检测图像中的物体并将物体裁剪下来:https://blog.csdn.net/liqiancao/article/details/55670749
基于颜色hsv的图像分割:https://blog.csdn.net/Mr_Dec/article/details/103160537
OpenCV中HSV颜色模型及颜色分量范围:https://www.cnblogs.com/wangyblzu/p/5710715.html
关于findContours的一些知识点:https://blog.csdn.net/m0_37350758/article/details/82016820
findContours函数参数详解:https://blog.csdn.net/dcrmg/article/details/51987348
minAreaRect函数:https://blog.csdn.net/qq_18343569/article/details/48000179
RotatedRect类详解:https://blog.csdn.net/u011574296/article/details/71405239