c++ - 计算RotatedRect OpenCV内白色像素的百分比
问题描述
如何计算 cv::RotatedRect 内白色像素的百分比?我的意思是,如何访问我的 cv::RotatedRect 中的单个像素。如果我能做到这一点,我会知道以后该怎么做。谢谢
我已经尝试过这个线程的解决方案,但我有例外。https://stackoverflow.com/a/28780359
std::vector<cv::RotatedRect> minRect(count.size());
for (int i = 0; i < count.size(); i++)
{
minRect[i] = cv::minAreaRect(cv::Mat(count[i]));
}
for (size_t i = 0; i < count.size(); i++){
if (cv::contourArea(count[i]) > 200) {
cv::Point2f rect_points[4];
minRect[i].points(rect_points);
// Now I'd like to calculate percentage of white pixels inside of RotatedRect, and if value returned by func would be smaller than 30%,continue;
for (int j = 0; j < 4; j++) {
cv::line(mask, rect_points[j], rect_points[(j + 1) % 4], (0, 255, 0), 1, 8);
}
}
}
解决方案
你可以:
- 处理由定义的子图像
cv::boundingRect
- 创建蒙版,其中旋转矩形内的所有点都是白色的
cv::fillConvexPoly
- 与原始图像进行逻辑与
- 计算白色像素的数量
cv::countNonZero
John Henkel提出的方法有效,但在我的(非常快的)测试中,它的速度要慢 10 到 40 倍。
在这两种方法的代码下方。您会发现结果存在细微差别,因为旋转矩形边框上的白色像素的处理方式不同。
#include <opencv2\opencv.hpp>
#include <chrono>
int main()
{
// Create binary image with random pixels b/W
cv::Mat1b img(5000, 5000);
cv::randu(img, cv::Scalar(0), cv::Scalar(256));
img = img > 127;
// Define a rotated rect
cv::Point2f center(2000, 2000);
cv::Size2f sz(1000, 500);
float angle = 30.f;
cv::RotatedRect rr(center, sz, angle);
// Get points
std::vector<cv::Point2f> points(4);
rr.points(points.data());
// Work on ROI
cv::Rect roi = rr.boundingRect();
// Area
float area = rr.size.width * rr.size.height;
//// DEBUG, Show rect
//cv::Mat3b out;
//cv::cvtColor(img, out, cv::COLOR_GRAY2BGR);
//for (int i = 0; i < 4; ++i) {
// cv::line(out, points[i], points[(i + 1) % 4], cv::Scalar(0, 0, 255));
//}
{
// --------------------
// Method @Miki
// --------------------
auto tic = std::chrono::high_resolution_clock::now();
cv::Mat1b sub_img = img(roi);
// Create rotated rect mask
cv::Mat1b mask(roi.size(), uchar(0));
std::vector<cv::Point> points_in_sub_image(4);
for (int i = 0; i < 4; ++i) {
points_in_sub_image[i] = cv::Point(points[i]) - roi.tl();
}
cv::fillConvexPoly(mask, points_in_sub_image, cv::Scalar(255));
// AND sub image with mask
cv::Mat1b inside_roi = sub_img & mask;
//// DEBUG, Draw green points
//for (int r = 0; r < sub_img.rows; ++r) {
// for (int c = 0; c < sub_img.cols; ++c) {
// if (inside_roi(r, c) > 0)
// {
// out(r + roi.y, c + roi.x) = cv::Vec3b(0, 255, 0);
// }
// }
//}
// Get actual count
int cnz = cv::countNonZero(inside_roi);
auto toc = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(toc - tic);
float percent_white_pixels = cnz / area;
std::cout << "percent_white_pixels: " << percent_white_pixels << " in " << elapsed.count() << " us" << std::endl;
}
{
// --------------------
// Method @John Henkel
// --------------------
auto tic = std::chrono::high_resolution_clock::now();
int cnz = 0;
for (int y = roi.y; y < roi.y + roi.height; ++y) {
for (int x = roi.x; x < roi.x + roi.width; ++x) {
if (
(img(y, x) > 0) &&
(cv::pointPolygonTest(points, cv::Point2f(x, y), false) >= 0.0)
)
{
// DEBUG, Draw blue points
//out(y, x) = cv::Vec3b(255, 0, 0);
++cnz;
}
}
}
auto toc = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(toc - tic);
float percent_white_pixels = cnz / area;
std::cout << "percent_white_pixels: " << percent_white_pixels << " in " << elapsed.count() << " us" << std::endl;
}
getchar();
return 0;
}
推荐阅读
- java - 如何修复 Spring Boot 应用程序中的 Websockets 和 Shedlock 兼容性
- python - 凹面罩到凸面
- python-3.x - 如何在 aws 云日志中打印异常堆栈跟踪
- c# - 当用户可以在 dotnet CORE 的多个位置拥有多个角色时,处理授权的最合适方法是什么
- c# - 如何在c#中获取音频文件的频率数组
- javascript - 如何修复解析错误:不能在异步函数之外使用关键字“await”
- excel - 将 excel 文件分成 5000 行的较小文件,每个文件不拆分行
- c++ - 如何解决“不一致的 dll 链接(C4273)”警告?
- angular - 使用枚举值时,Angular ngClass 不起作用
- azure - 如何在 sidecar inject-config.yaml 中更改 istio 全局参数