単一ブロブの場合、問題は次のように公式化できます。find the largest rectangle containing only zeros in a matrix。
ブロブの中で最大の軸指向の矩形を見つけるには、findMinRect
のmy other answerを参照してください。このコードは、PythonのオリジナルのC++での移植で、hereです。
次に、同じ色のすべてのブロブを見つけることです。あなたの画像がJPEGで圧縮が多くの人工的な色を境界線の近くに作成するため、これはややこしいことです。だから、アルゴリズムが動作することを示すために、pngイメージ(下に示す)を作成しました。圧縮アーチファクトのない画像を提供するのはあなた次第です。
次に、各色のマスクを作成し、このマスク内の各ブロブの接続コンポーネントを見つけ、各ブロブの最小矩形を計算するだけです。
初期画像:ここで
私は色で分け、各ブロブが見つかりrectsを示しました。次に、各色の最大矩形か、各色の最大矩形のいずれかの矩形だけを取り出すことができます。
結果:
ここ
コード:
#include <opencv2/opencv.hpp>
#include <algorithm>
#include <set>
using namespace std;
using namespace cv;
// https://stackoverflow.com/a/30418912/5008845
Rect findMinRect(const Mat1b& src)
{
Mat1f W(src.rows, src.cols, float(0));
Mat1f H(src.rows, src.cols, float(0));
Rect maxRect(0, 0, 0, 0);
float maxArea = 0.f;
for (int r = 0; r < src.rows; ++r)
{
for (int c = 0; c < src.cols; ++c)
{
if (src(r, c) == 0)
{
H(r, c) = 1.f + ((r>0) ? H(r - 1, c) : 0);
W(r, c) = 1.f + ((c>0) ? W(r, c - 1) : 0);
}
float minw = W(r, c);
for (int h = 0; h < H(r, c); ++h)
{
minw = min(minw, W(r - h, c));
float area = (h + 1) * minw;
if (area > maxArea)
{
maxArea = area;
maxRect = Rect(Point(c - minw + 1, r - h), Point(c + 1, r + 1));
}
}
}
}
return maxRect;
}
struct lessVec3b
{
bool operator()(const Vec3b& lhs, const Vec3b& rhs) {
return (lhs[0] != rhs[0]) ? (lhs[0] < rhs[0]) : ((lhs[1] != rhs[1]) ? (lhs[1] < rhs[1]) : (lhs[2] < rhs[2]));
}
};
int main()
{
// Load image
Mat3b img = imread("path_to_image");
// Find unique colors
set<Vec3b, lessVec3b> s(img.begin(), img.end());
// Divide planes of original image
vector<Mat1b> planes;
split(img, planes);
for (auto color : s)
{
// Create a mask with only pixels of the given color
Mat1b mask(img.rows, img.cols, uchar(255));
for (int i = 0; i < 3; ++i)
{
mask &= (planes[i] == color[i]);
}
// Find blobs
vector<vector<Point>> contours;
findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); ++i)
{
// Create a mask for each single blob
Mat1b maskSingleContour(img.rows, img.cols, uchar(0));
drawContours(maskSingleContour, contours, i, Scalar(255), CV_FILLED);
// Find minimum rect for each blob
Rect box = findMinRect(~maskSingleContour);
// Draw rect
Scalar rectColor(color[1], color[2], color[0]);
rectangle(img, box, rectColor, 2);
}
}
imshow("Result", img);
waitKey();
return 0;
}
あなたは非圧縮画像を提供する場合、私はあなたのイメージにも私の答えに結果を投稿します。 – Miki