实际项目中需要寻找这些线段的端点:
1、首先对图片进行细化操作,这样获得直线还是比较清晰的。
2、在使用霍夫变换直线检测的时候,根据本图的先验知识,那就是直线在交点位置产生了急剧的变化,所以调大其第3参数,也就是角度变化。
下一步就可以进行端点检测。这里绘制出目前检测出来的端点:
端点的检测,需要比对的是每一个端点的相对位置。一般来说,我都选用更加靠近中间位置的端点作为结果。
void thin(const Mat &src, Mat &dst, const int iterations = 100);//Mat 需要为DEPTH_8U型二值图
//将 DEPTH_8U型二值图像进行细化 经典的Zhang并行快速细化算法
//细化算法
void thin(const Mat &src, Mat &dst, const int iterations) {
const int height = src.rows - 1;
const int width = src.cols - 1;
//拷贝一个数组给另一个数组
if (src.data != dst.data)
src.copyTo(dst);
int n = 0, i = 0, j = 0;
Mat tmpImg;
uchar *pU, *pC, *pD;
bool isFinished = false;
for (n = 0; n < iterations; n++) {
dst.copyTo(tmpImg);
isFinished = false; //一次 先行后列扫描 开始
//扫描过程一 开始
for (i = 1; i < height; i++) {
pU = tmpImg.ptr<uchar>(i - 1);
pC = tmpImg.ptr<uchar>(i);
pD = tmpImg.ptr<uchar>(i + 1);
for (int j = 1; j < width; j++) {
if (pC[j] > 0) {
int ap = 0;
int p2 = (pU[j] > 0);
int p3 = (pU[j + 1] > 0);
if (p2 == 0 && p3 == 1)
ap++;
int p4 = (pC[j + 1] > 0);
if (p3 == 0 && p4 == 1)
ap++;
int p5 = (pD[j + 1] > 0);
if (p4 == 0 && p5 == 1)
ap++;
int p6 = (pD[j] > 0);
if (p5 == 0 && p6 == 1)
ap++;
int p7 = (pD[j - 1] > 0);
if (p6 == 0 && p7 == 1)
ap++;
int p8 = (pC[j - 1] > 0);
if (p7 == 0 && p8 == 1)
ap++;
int p9 = (pU[j - 1] > 0);
if (p8 == 0 && p9 == 1)
ap++;
if (p9 == 0 && p2 == 1)
ap++;
if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) > 1 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) < 7) {
if (ap == 1) {
if ((p2*p4*p6 == 0) && (p4*p6*p8 == 0)) {
dst.ptr<uchar>(i)[j] = 0;
isFinished = true;
}
}
}
}
} //扫描过程一 结束
dst.copyTo(tmpImg);
//扫描过程二 开始
for (i = 1; i < height; i++) {
pU = tmpImg.ptr<uchar>(i - 1);
pC = tmpImg.ptr<uchar>(i);
pD = tmpImg.ptr<uchar>(i + 1);
for (int j = 1; j < width; j++) {
if (pC[j] > 0) {
int ap = 0;
int p2 = (pU[j] > 0);
int p3 = (pU[j + 1] > 0);
if (p2 == 0 && p3 == 1)
ap++;
int p4 = (pC[j + 1] > 0);
if (p3 == 0 && p4 == 1)
ap++;
int p5 = (pD[j + 1] > 0);
if (p4 == 0 && p5 == 1)
ap++;
int p6 = (pD[j] > 0);
if (p5 == 0 && p6 == 1)
ap++;
int p7 = (pD[j - 1] > 0);
if (p6 == 0 && p7 == 1)
ap++;
int p8 = (pC[j - 1] > 0);
if (p7 == 0 && p8 == 1)
ap++;
int p9 = (pU[j - 1] > 0);
if (p8 == 0 && p9 == 1)
ap++;
if (p9 == 0 && p2 == 1)
ap++;
if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) > 1 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) < 7) {
if (ap == 1) {
if ((p2*p4*p8 == 0) && (p2*p6*p8 == 0)) {
dst.ptr<uchar>(i)[j] = 0;
isFinished = true;
}
}
}
}
}
} //一次 先行后列扫描完成
//如果在扫描过程中没有删除点,则提前退出
if (isFinished == false)
break;
}
}
}
// end of thin
int main()
{
RNG rng = RNG(12345); //随机数
Mat src = imread("f:/template/lines.png");
Mat gray; Mat bin; Mat matThin;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, bin, 0, 255, THRESH_BINARY_INV);
thin(bin, matThin);
imshow("matThin", matThin);//展示提取的边缘
vector<Vec4f> lines;//存储直线的容器
Mat dst = Mat(src.size(), src.type(), Scalar(255, 255, 255));//创建大小和类型都与源图像相同的背景为白色的图像
HoughLinesP(matThin, lines, 1, CV_PI / 180, 60, 0, 8);//霍夫变换直线检测
for (int i = 0; i < lines.size(); i++) {
Scalar lineColor = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
Vec4f l = lines[i];
line(dst, Point(l[0], l[1]), Point(l[2], l[3]), lineColor, 3, LINE_AA);//在创建的白色图像上画直线
circle(src, Point(l[0], l[1]), 3,Scalar(0,0,255), 2);
circle(src, Point(l[2], l[3]), 3,Scalar(0,255,0), 1);
}
int i = 0;
}