现有这样一个场景:任意一个掩膜,在掩膜上绘制一个内圆(完整地圆),我需要输入这个内圆上的任意一点,然后逆时针的依次保存整个内圆的位置。代码如下:
#include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <time.h>
using namespace std;
using namespace cv;
/* 使用场景:任意一个掩膜,在掩膜上绘制一个内圆(完整地圆),我需要输入这个内圆上的任意一点,然后逆时针的依次保存整个内圆的位置
* 基本思路:
* 1. 确定寻径的方向为逆时针
* 2. 通过输入的x,y和圆心点来确定象限值
* 3. 确定了象限值就可以比较容易的判断出圆的下一个点的方向。如在第三象限的点,下一个点的方向只可能为右,下,右下
* 4. 在初始进入函数时将起点值存入容器,函数内每次执行完找点后需要判断是否为起点,若是,则退出,否则将点放入容器,继续判断是否需要更换象限
*/
// 根据xy和中心点,获取象限值
int getQuadrantValue(const int x, const int y, const Point &circleCenter)
{
if (x <= circleCenter.x && y < circleCenter.y)
return 2;
else if (x < circleCenter.x && y >= circleCenter.y)
return 3;
else if (circleCenter.x < x && circleCenter.y >= y)
return 1;
return 4;
}
void test10(Mat mask, Point startPoint, Point circleCenter, int radius, std::vector<cv::Point>& ret)
{
// 绘制一个圆
cv::circle(mask, circleCenter, radius, cv::Scalar(255));
int x = startPoint.x;
int y = startPoint.y;
int type = getQuadrantValue(x, y, circleCenter);
ret.push_back(startPoint);
while (true) {
switch (type) {
case 1: {
if (x > 0 && mask.at<uchar>(y, x - 1) == 255) --x;
else if (y > 0 && x > 0 && mask.at<uchar>(y - 1, x - 1) == 255) --x, --y;
else if (y > 0 && mask.at<uchar>(y - 1, x) == 255) --y;
}; break;
case 2: {
if (x > 0 && mask.at<uchar>(y, x - 1) == 255) --x;
else if (x > 0 && mask.at<uchar>(y + 1, x - 1) == 255) --x, ++y;
else if (y + 1 < mask.rows && mask.at<uchar>(y + 1, x) == 255) ++y;
}; break;
case 3: {
if (y + 1 < mask.rows && x + 1 < mask.cols && mask.at<uchar>(y + 1, x + 1) == 255) ++x, ++y;
else if (x + 1 < mask.cols && mask.at<uchar>(y, x + 1) == 255) ++x;
else if (y + 1 < mask.rows && mask.at<uchar>(y + 1, x) == 255) ++y;
}; break;
case 4: {
if (x + 1 < mask.cols && mask.at<uchar>(y, x + 1) == 255) ++x;
else if (x + 1 < mask.cols && y > 0 && mask.at<uchar>(y - 1, x + 1) == 255) ++x, --y;
else if (y > 0 && mask.at<uchar>(y - 1, x) == 255) --y;
}; break;
}
// 若等于起点,则退出
if (x == startPoint.x && y == startPoint.y)
break;
ret.push_back(cv::Point(x, y));
// 校验是否需要更改象限
if (type != getQuadrantValue(x, y, circleCenter)) {
type = getQuadrantValue(x, y, circleCenter);
}
}
}
int main()
{
cv::Mat mask = cv::Mat::zeros(cv::Size(2000,2000), CV_8UC1);
cv::Mat testMask = cv::Mat::zeros(cv::Size(2000, 2000), CV_8UC1);
cv::Point circleCenter = cv::Point(1000, 1000);
int radius = 800;
cv::Point startPoint(1000,1800);
cout << "startPoint:" << startPoint << endl;
std::vector<cv::Point> ret;
clock_t s, e;
s = clock();
test10(mask, startPoint, circleCenter, radius, ret);
e = clock();
cout << "time:" << e - s << endl;
// 根据位置赋值,能还原出掩膜
for (uint i = 0; i < ret.size(); ++i) {
testMask.at<uchar>(ret[i]) = 255;
if (i % 10 == 0) {
int ppp = 1000;
}
std::cout << "value" << i << " is " << ret[i] << std::endl;
}
std::cout << "fill pixel finshed !" << std::endl;
system("pause");
return 0;
}