0、算子描述
算子接受一个旋转矩形作为ROI(兴趣区域),接受一个或者多个旋转矩形作为Masks(掩膜,掩膜遮蔽的像素不计入算子计算),所以有效检测区域为ROI减去Masks。计算有效检测区域内的像素平均值。将该像素平均值与参考值进行比较,若该像素平均值落与参考值的上下限百分比内,则算子返回true,否则返回false。注:所有ROI和mask的位置和角度都是相对于原图的图像坐标的。
1、解决思路
使用判别矩阵,方法如下。
roi区域图如下,用白色掩膜表示。
mask图如下,用黑色掩膜表示。
roi和mask图如下。其中白色表示,roi区域图,黑色表示mask区域图。
掩膜的判别矩阵如下(图像命名出现错误,不要在意这些细节)。
截取以后的图像如下图所示:
截取以后的判别矩阵如下图所示
很显然,判别矩阵和打了掩膜以后截取的roi图在像素上存在关联,判别矩阵的黑色区域对应的是roi区域需要计算的像素,白色区域是打掩膜区域。因此很容易用cv::mean()求得均值。
关于cv::mean()的调用如下:
cv::Scalar mean = cv::mean(image, mask);
其中,mask是与iamge一样大小的矩阵,其中的数值为0-255,可以理解为一个判别矩阵。
2、代码实现
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
using namespace cv;
// 在掩膜上绘制mask旋转矩形,用0像素填充绘制
Mat DrawMask(Mat& image, RotatedRect rotatedRectangle)
{
Mat new_image;
image.copyTo(new_image);
Scalar color = Scalar::all(0); // 全部填充黑色
Point2f vertices2f[4];
rotatedRectangle.points(vertices2f);
Point vertices[4];
for (int i = 0; i < 4; i++)
{
vertices[i] = vertices2f[i];
}
fillConvexPoly(new_image, vertices, 4, color);
return new_image;
}
// 绘制ROI区域
Mat DrawRoi(Mat& image, RotatedRect rotatedRectangle)
{
Mat new_image;
image.copyTo(new_image);
Scalar color = Scalar::all(200); // 全部填充灰色
Point2f vertices2f[4];
rotatedRectangle.points(vertices2f);
Point vertices[4];
for (int i = 0; i < 4; i++)
{
vertices[i] = vertices2f[i];
}
fillConvexPoly(new_image, vertices, 4, color);
return new_image;
}
// 判别矩阵
Mat judge(Mat& image, RotatedRect rotatedRectangle)
{
int h = image.rows;
int w = image.cols;
Mat judge_metrix(h, w, CV_8UC1, Scalar(255)); // 白色
Scalar color = Scalar::all(0); // 黑色
Point2f vertices2f[4];
rotatedRectangle.points(vertices2f);
Point vertices[4];
for (int i = 0; i < 4; i++)
{
vertices[i] = vertices2f[i];
}
fillConvexPoly(judge_metrix, vertices, 4, color);
return judge_metrix;
}
// 求均值处理
void gray_operator(Mat& image, RotatedRect rotatedRectangle)
{
Mat image_mask = DrawMask(image, rotatedRectangle); // 打掩膜图像
Mat judge_metrix = judge(image, rotatedRectangle); // 判别矩阵
int h = image.rows;
int w = image.cols;
int sum = 0; // 总像素
int pixel = 0; // 总的像素值
for (int row = 0; row < h; row++)
{
for (int col = 0; col < w; col++)
{
if (judge_metrix.at<uchar>(row, col) == 0)
{
sum += 1;
pixel += image_mask.at<uchar>(row, col);
}
}
}
float average = pixel / sum;
cout << "平均像素为:" << average;
}
// 截取图像
Mat cropped_roi(Mat& image, RotatedRect rect)
{
Mat M, rotated, cropped;
float angle = rect.angle;
Size rect_size = rect.size;
M = getRotationMatrix2D(rect.center, angle, 1.0);
warpAffine(image, rotated, M, image.size(), INTER_CUBIC);
getRectSubPix(rotated, rect_size, rect.center, cropped);
return cropped;
//namedWindow("cropped", WINDOW_FREERATIO);
//imshow("cropped", cropped);
}
int main()
{
Mat src = imread("D:/image/mask_average.JPG");
if (src.empty())
{
printf("could not load the image\n");
return -1;
}
Mat src_gray;
cvtColor(src, src_gray, COLOR_BGR2GRAY);
RotatedRect rRect1 = RotatedRect(Point2f(200, 100), Size2f(200, 100), 30);
RotatedRect rRect2 = RotatedRect(Point2f(200, 100), Size2f(200, 100), -30);
Mat new_image = DrawMask(src_gray, rRect1); // 打上掩膜的图片
Mat roi_image = DrawRoi(src_gray, rRect2); // 绘制ROI的图片
Mat judge_metrix_mask = judge(src_gray, rRect1); // 掩膜判别矩阵
Mat judge_metrix_roi = judge(src_gray, rRect2);
Mat cropped = cropped_roi(new_image, rRect2);
imshow("cropped", cropped);
Mat mask_cropped = cropped_roi(judge_metrix_mask, rRect2);
imshow("cropped_roi", mask_cropped);
float result = mean(cropped, mask_cropped == 255)[0];
cout << "平均像素为:" << result << endl;
/*imshow("src", src);
imshow("new_image", new_image);
imshow("掩膜判别矩阵", judge_metrix_mask);
imshow("roi区域", roi_image);
imshow("roi判别矩阵", judge_metrix_roi);*/
//gray_operator(src_gray, rRect1);
waitKey(0);
return 0;
}