目录
一,识别黑点
这是一个比较简单的场景,只需要识别一些固定位置是目标色块还是背景色。
图片:
识别目标是网格图中,每个正方形角点、边中点、对角线交点是否有大黑点(黑色块)。
思路:
直接下采样,然后根据对应位置的像素值即可判断。
int main()
{
int r = 7, c = 7, imgSize = 200, pixTh = 50;
Mat img = imread("D:/img.jpg",0);
resize(img, img, Size(imgSize, imgSize), 0, 0);
double stepR = imgSize / 2.0 / r, stepC = imgSize / 2.0 / c;
for (int i = 0; i < imgSize; i += stepR) {
for (int j = 0; j < imgSize; j += stepC) {
cout << (int(img.at<uchar>(i, j))> pixTh ? " " : "*")<<" ";
}
cout << endl;
}
imshow("img", img);
waitKey(0);
return 0;
}
输出效果:
二,搜索求解
我的解决思路是分3步:
(1)把所有k个给定点分为两种,一种是正方形内的点,一种是正方形边上中点或角点。
对于正方形内的点,可以确定一个孤立的格子,剩下的所有格子数量一定是偶数2x。
(2)对2x个剩下格子进行分组,分为x组,每组2个格子的重心都是给定点。
找出满足条件的所有分组,逐一检查是不是答案即可。
(3)对于2x个格子的每一种分组,加上孤立格子后重新分为k组,即每个给定点所属的所有格子。
检查连通性,只要连通性没问题就是最终答案。
struct Point
{
int x, y;
bool operator<(const Point&p)const
{
if (x == p.x)return y < p.y;
return x < p.x;
}
};
//grid边长为2,求imageId ga和gb的重心
Point getMid(int r, int c, int ga, int gb)
{
int x = ga % c + gb % c + 1;
int y = r * 2 - 1 - ga / c - gb / c;
return { x,y };
}
bool isConnect(int r, int c, vector<int>&v)
{
Union opt(r*c);
for (int i = 0; i < v.size(); i++)for (int j = 0; j < v.size(); j++) {
if (v[j] - v[i] == 1 || v[j] - v[i] == c)opt.merge(v[j], v[i]);
}
return opt.getRootNums() == r * c - v.size() + 1;
}
bool isConnect(int r, int c, vector<Edge>&ve)
{
map<Point, vector<int>>mp;
for (auto e : ve) {
if (e.a < r*c && e.b < r*c) {
mp[getMid(r, c, e.a, e.b)].push_back(e.a);
mp[getMid(r, c, e.a, e.b)].push_back(e.b);
}
else {
mp[getMid(r, c, e.a, e.a)].push_back(e.a);
}
}
for (auto mi : mp) {
if (!isConnect(r, c, mi.second))return false;
}
return true;
}
vector<vector<int>> solve(int r, int c, vector<Point>&v)
{
int num = r * c;
map<int, int>m;//孤立的格子
map<Point, int>mp;
vector<Edge> ve;
for (int i = 0; i < v.size();i++) {
if (v[i].x % 2 && v[i].y % 2) {
int id = (r - v[i].y / 2 - 1)*c + v[i].x / 2;
ve.push_back(Edge{ id,num,0 });
m[id] = num++;
}
mp[v[i]] = i + 1;
}
for (int i = 0; i < r*c; i++) {
for (int j = i + 1; j < r*c; j++) {
if (m[i] == 0 && m[j] == 0 && mp[getMid(r, c, i, j)])ve.push_back(Edge{ i,j,0 });
}
}
vector<vector<Edge>> edges = GetEdgeCover(num / 2, ve);
vector<vector<int>>ans;
for (auto edge : edges) {
if (isConnect(r, c, edge))//校验连通性
{
ans.resize(v.size());
for (auto e : edge) {
if (e.a < r*c && e.b < r*c) {
int id = mp[getMid(r, c, e.a, e.b)] - 1;
ans[id].push_back(e.a);
ans[id].push_back(e.b);
}
else {
int id = mp[getMid(r, c, e.a, e.a)] - 1;
ans[id].push_back(e.a);
}
}
return ans;
}
}
return ans;
}
void test1()
{
vector<Point>v{ {2,2},{5,1},{5,3} };
Print(solve(2, 3, v));//0134 2 5
}
void test2()
{
vector<Point>v{ {2,2},{1,7},{3,9} ,{7,2},{9,5},{6,7} };
Print(solve(5, 5, v));
}
三,显示答案
const int r = 7, c = 7;
int x[r][c];
void show(int pix,int step)
{
Mat img = Mat(Size(pix * c, pix * r), CV_8UC1);
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
for (int r = pix * i; r < pix * (i + 1); r++) {
for (int c = pix * j; c < pix * (j + 1); c++) {
img.at<uchar>(r, c) = step * x[i][j];
}
}
}
cout << endl;
}
imshow("ans", img);
}
四,完整代码
//grid边长为2,求imageId ga和gb的重心
Point2 getMid(int r, int c, int ga, int gb)
{
int x = ga % c + gb % c + 1;
int y = r * 2 - 1 - ga / c - gb / c;
return { x,y };
}
bool isConnect(int r, int c, vector<int>& v)
{
Union opt(r * c);
for (int i = 0; i < v.size(); i++)for (int j = 0; j < v.size(); j++) {
if (v[j] - v[i] == 1 || v[j] - v[i] == c)opt.merge(v[j], v[i]);
}
return opt.getRootNums() == r * c - v.size() + 1;
}
bool isConnect(int r, int c, vector<Edge>& ve)
{
map<Point2, vector<int>>mp;
for (auto e : ve) {
if (e.a < r * c && e.b < r * c) {
mp[getMid(r, c, e.a, e.b)].push_back(e.a);
mp[getMid(r, c, e.a, e.b)].push_back(e.b);
}
else {
mp[getMid(r, c, e.a, e.a)].push_back(e.a);
}
}
for (auto mi : mp) {
if (!isConnect(r, c, mi.second))return false;
}
return true;
}
vector<vector<int>> solve(int r, int c, vector<Point2>& v)
{
int num = r * c;
map<int, int>m;//孤立的格子
map<Point2, int>mp;
vector<Edge> ve;
for (int i = 0; i < v.size(); i++) {
if (v[i].x % 2 && v[i].y % 2) {
int id = (r - v[i].y / 2 - 1) * c + v[i].x / 2;
ve.push_back(Edge{ id,num,0 });
m[id] = num++;
}
mp[v[i]] = i + 1;
}
for (int i = 0; i < r * c; i++) {
for (int j = i + 1; j < r * c; j++) {
if (m[i] == 0 && m[j] == 0 && mp[getMid(r, c, i, j)])ve.push_back(Edge{ i,j,0 });
}
}
vector<vector<Edge>> edges = GetEdgeCover(num / 2, ve);
vector<vector<int>>ans;
for (auto edge : edges) {
if (isConnect(r, c, edge))//校验连通性
{
ans.resize(v.size());
for (auto e : edge) {
if (e.a < r * c && e.b < r * c) {
int id = mp[getMid(r, c, e.a, e.b)] - 1;
ans[id].push_back(e.a);
ans[id].push_back(e.b);
}
else {
int id = mp[getMid(r, c, e.a, e.a)] - 1;
ans[id].push_back(e.a);
}
}
return ans;
}
}
return ans;
}
const int r = 7, c = 7;
int x[r][c];
void show(int pix, int step)
{
Mat img = Mat(Size(pix * c, pix * r), CV_8UC1);
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
for (int r = pix * i; r < pix * (i + 1); r++) {
for (int c = pix * j; c < pix * (j + 1); c++) {
img.at<uchar>(r, c) = step * x[i][j];
}
}
}
cout << endl;
}
imshow("ans", img);
}
int main()
{
int imgSize = 200, pixTh = 50;
Mat img = imread("D:/img.jpg", 0);
img = img(Rect(25, 456, 1030, 1030));
resize(img, img, Size(imgSize, imgSize), 0, 0);
double stepR = imgSize / 2.0 / r, stepC = imgSize / 2.0 / c;
vector<Point2> vp;
for (int i = 0; i * stepR < imgSize; i++) {
for (int j = 0; j * stepC < imgSize; j++) {
if (int(img.at<uchar>(i * stepR, j * stepC)) > pixTh)cout << " ";
else {
cout << "* ";
vp.push_back(Point2{ j, r * 2 - i });
}
}
cout << endl;
}
vector<vector<int>>v = solve(r, c, vp);
for (int i = 0; i < v.size(); i++) {
for (auto vi : v[i])x[vi / c][vi % c] = i;
}
show(50, 255 / v.size());
imshow("img", img);
waitKey(0);
return 0;
}
输入:
运行效果: