OpenCV实现均值算子

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值