正如标题所说,我试图在 cv::Mat 的某个区域(即 RotatedRect 内)中找到非零像素的数量。
对于常规的 Rect,可以简单地在 ROI 上使用 countNonZeroPixels。然而,ROI 只能是常规(非旋转)矩形。
另一个想法是绘制旋转的矩形并将其用作蒙版。然而,openCV 既不支持绘制旋转的矩形也不支持 countNonZeroPixels 接受掩码。
有没有人有如何优雅地解决这个问题的解决方案?
谢谢 !
正如标题所说,我试图在 cv::Mat 的某个区域(即 RotatedRect 内)中找到非零像素的数量。
对于常规的 Rect,可以简单地在 ROI 上使用 countNonZeroPixels。然而,ROI 只能是常规(非旋转)矩形。
另一个想法是绘制旋转的矩形并将其用作蒙版。然而,openCV 既不支持绘制旋转的矩形也不支持 countNonZeroPixels 接受掩码。
有没有人有如何优雅地解决这个问题的解决方案?
谢谢 !
好的,这是我的第一个看法。
这个想法是将图像反向旋转到矩形的旋转,然后在拉直的矩形上应用 roi。
您可以通过在旋转之前应用另一个 roi 来加快速度,以避免旋转整个图像......
#include <highgui.h>
#include <cv.h>
// From http://stackoverflow.com/questions/2289690/opencv-how-to-rotate-iplimage
cv::Mat rotateImage(const cv::Mat& source, cv::Point2f center, double angle)
{
cv::Mat rot_mat = cv::getRotationMatrix2D(center, angle, 1.0);
cv::Mat dst;
cv::warpAffine(source, dst, rot_mat, source.size());
return dst;
}
int main()
{
cv::namedWindow("test1");
// Our rotated rect
int x = 300;
int y = 350;
int w = 200;
int h = 50;
float angle = 47;
cv::RotatedRect rect = cv::RotatedRect(cv::Point2f(x,y), cv::Size2f(w,h), angle);
// An empty image
cv::Mat img = cv::Mat(cv::Size(640, 480), CV_8UC3);
// Draw rotated rect as an ellipse to get some visual feedback
cv::ellipse(img, rect, cv::Scalar(255,0,0), -1);
// Rotate the image by rect.angle * -1
cv::Mat rotimg = rotateImage(img, rect.center, -1 * rect.angle);
// Set roi to the now unrotated rectangle
cv::Rect roi;
roi.x = rect.center.x - (rect.size.width / 2);
roi.y = rect.center.y - (rect.size.height / 2);
roi.width = rect.size.width;
roi.height = rect.size.height;
cv::imshow("test1", rotimg(roi));
cv::waitKey(0);
}
一种完全不同的方法可能是旋转图像(沿相反方向),并且仍然使用矩形 ROI 和 countNonZeroPixels。唯一的问题是您必须围绕 ROI 中心的枢轴旋转图像...
为了更清楚,请参阅附件示例:
为了避免在类似任务中旋转,我使用以下函数遍历 RotatedRect 中的每个像素:
double filling(Mat& img, RotatedRect& rect){
double non_zero = 0;
double total = 0;
Point2f rect_points[4];
rect.points( rect_points );
for(Point2f i=rect_points[0];norm(i-rect_points[1])>1;i+=(rect_points[1]-i)/norm((rect_points[1]-i))){
Point2f destination = i+rect_points[2]-rect_points[1];
for(Point2f j=i;norm(j-destination)>1;j+=(destination-j)/norm((destination-j))){
if(img.at<uchar>(j) != 0){
non_zero+=1;
}
total+=1;
}
}
return non_zero/total;
}
它看起来像通常在矩形上的迭代,但在每一步中,我们将单位 1px 向量添加到当前点,指向目的地。
这个循环不会遍历所有点并跳过几个像素,但这对我的任务来说没问题。
UPD:最好使用 LineIterator 进行迭代:
Point2f rect_points[4];
rect.points(rect_points);
Point2f x_start = rect_points[0];
Point2f x_end = rect_points[1];
Point2f y_direction = rect_points[3] - rect_points[0];
LineIterator x = LineIterator(frame, x_start, x_end, 4);
for(int i = 0; i < x.count; ++i, ++x){
LineIterator y = LineIterator(frame, x.pos(), x.pos() + y_direction, 4);
for(int j=0; j < y_count; j++, ++y){
Vec4b pixel = frame.at<Vec4b>(y.pos);
/* YOUR CODE HERE */
}
}