对称之美自动求解

目录

一,识别黑点

二,搜索求解

三,显示答案

四,完整代码


一,识别黑点

 这是一个比较简单的场景,只需要识别一些固定位置是目标色块还是背景色。

图片:

识别目标是网格图中,每个正方形角点、边中点、对角线交点是否有大黑点(黑色块)。

思路:

直接下采样,然后根据对应位置的像素值即可判断。

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;
}

输入:

运行效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值