曲线/路径骨架二值图像处理 [英] Process on curve/path skeleton binary image

查看:275
本文介绍了曲线/路径骨架二值图像处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图开发一个可以处理图像骨架的路径/曲线的代码。我想在两点之间有一个来自骨架的点的向量。

I am trying to develop a code that can process on path/curve of a skeleton of an image . I want to have a vector of points from the skeleton between two points .

此代码在添加一些点后结束。我没有找到解决方案。

This code ends after adding some points .I didn't find a solution for it .

 #include "opencv2/highgui/highgui.hpp"
 #include "opencv2/imgproc/imgproc.hpp"
 #include "opencv2/imgproc/imgproc_c.h"
 #include <opencv2/legacy/compat.hpp>
 #include <opencv2/core/core.hpp>
 #include <iostream>
 #include <cmath>
 #include <list>
 using namespace cv;
 using namespace std;

  //this method to find the 8-neighbors of a point from image 
 vector<Point> search8Neighbor(cv::Mat mat,Point startPoint)
 {
  vector<Point> segment;
  Point p;
    //uchar p1 = mat.at<uchar>(startPoint.x, startPoint.y);
    uchar p2 = mat.at<uchar>(startPoint.x-1, startPoint.y);
    uchar p3 = mat.at<uchar>(startPoint.x-1, startPoint.y+1);
    uchar p4 = mat.at<uchar>(startPoint.x, startPoint.y+1);
    uchar p5 = mat.at<uchar>(startPoint.x+1, startPoint.y+1);
    uchar p6 = mat.at<uchar>(startPoint.x+1, startPoint.y);
    uchar p7 = mat.at<uchar>(startPoint.x+1, startPoint.y-1);
    uchar p8 = mat.at<uchar>(startPoint.x, startPoint.y-1);
    uchar p9 = mat.at<uchar>(startPoint.x-1, startPoint.y-1);

    //if(p1==255) segment.push_back(startPoint.x, startPoint.y);
    if (p2 == 255) {
            p.x=startPoint.x-1;
            p.y=startPoint.y;
            segment.push_back(p);
    }
    if(p3==255) {
            p.x=startPoint.x-1;
            p.y=startPoint.y+1;
            segment.push_back(p);
    }

    if(p4==255) {
            p.x=startPoint.x;
            p.y=startPoint.y+1;
            segment.push_back(p);
    }

    if(p5==255) {
            p.x=startPoint.x+1;
            p.y=startPoint.y+1;
            segment.push_back(p);
    }

    if(p6==255) {
            p.x=startPoint.x+1;
            p.y=startPoint.y;
            segment.push_back(p);
    }
    if(p7==255) {
            p.x=startPoint.x+1;
            p.y=startPoint.y-1;
            segment.push_back(p);
    }
    if(p8==255){
            p.x=startPoint.x;
            p.y=startPoint.y-1;
            segment.push_back(p);
    }

    if(p9==255) {
            p.x=startPoint.x-1;
            p.y=startPoint.y-1;
            segment.push_back(p);
    }

    return segment ;

 }
  //this method return a vector of points from a skeleton that contains all the points 
 //  between a start point "peak" and an end point 
 //this method use the idea of Breadth first search 
  vector<Point> traceLine(Mat img , Point peak)
{
    vector<Point> vect1;
    vector<Point> vect2;
    img.at<uchar>(peak.x,peak.y)=0;//
    vect1.push_back(peak);//add peak to vect1
    while(vect1.size() != 0)
        {
        Point p=vect1[0];
        vect1.erase(vect1.begin());
        vect2.push_back(p);
        vector<Point> vectN;
        vectN=search8Neighbor(img,p);
        vector<Point>::iterator it;
        it = vect1.begin();
        //cout<<vectN.size()<<endl;
        for(int i=0;i<vectN.size();i++)
            {
                 img.at<uchar>(vectN[i].x,vectN[i].y)=0;
                vect1.insert(it,vectN[i]);

            }
        }
return vect2;
}

int main( int argc, char** argv )
{
cv::Mat im = cv::imread("aa.jpg",0);
if (im.empty())
return -1;
 cv::Mat img;
cv::threshold(im, img, 155, 255, CV_THRESH_BINARY);
vector<Point> vect1;
Point p;
p.x=20;
p.y=30;
if(mat.at<uchar>(p.x-1, p.y)==255)
vect1=traceLine(img,p);
imshow("image",im);
cv::waitKey();
return 0 ;
}


推荐答案

正常的行/列方式为矩阵,所以你想要 mat.at (y,x),而不是 mat.at

A Mat is indexed in the normal row/col way for matrices, so you want mat.at<uchar>(y, x), not mat.at<uchar>(x, y), or confusion will result.

您在哪里:

vector<Point>::iterator it;
it = vect1.begin();
...
for(...)
    vect1.insert(it,vectN[i]);

如果插入导致缓冲区被重新分配,这将会中断,因为它然后指向一些内存已被解除分配,或者可能被重新分配给别的东西。
而不是使用

this will break if the insert causes the buffer to be reallocated, because it then points at some memory that has been deallocated, or perhaps reallocated to something else. Instead use

 vect1.insert(vect1.begin(),vectN[i]);

(这将给你的程序似乎做的稍微不同的顺序)或使用 push_back()来实际获取广度优先行为。

(which will give slightly different order to what your program seems to do) or use push_back() to actually get breadth first behavior.

最大的问题是search8Neighbor uchar p2 = mat.at 如果startPoint指向图片?你将引用图像之外的像素,程序将移动,直到发生异常。在这里,您需要检查图片中的位置,并确保您不包括附近图片外的像素。

The biggest issue is in search8Neighbor(). Where you have uchar p2 = mat.at<uchar>(startPoint.x-1, startPoint.y); what happens if startPoint refers to a pixel at the edge of the image? You will be referring to pixels outside the image and the program will wander off until an exception occurs. Here you need to check where you are in the image and make sure you do not include pixels from outside the image in the neighborhood.

编辑
我不相信的代码不会工作,如果改变,因为我说。
我实现了修复,它的工作原理:

EDIT I didn't believe the code wouldn't work if changed as I said. I have implemented the fixes and it works:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include <opencv2/legacy/compat.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <cmath>
#include <list>
using namespace cv;
using namespace std;

 // Find the 8-neighbors of a point from image.
 vector<Point> search8Neighbor(cv::Mat mat,Point startPoint)
 {
    vector<Point> neighbors;
    vector<Point> offsets;
    offsets.push_back(Point(-1,  0)); // p2
    offsets.push_back(Point(-1,  1)); // p3
    offsets.push_back(Point( 0,  1)); // p4
    offsets.push_back(Point( 1,  1)); // p5
    offsets.push_back(Point( 1,  0)); // p6
    offsets.push_back(Point( 1, -1)); // p7
    offsets.push_back(Point( 0, -1)); // p8
    offsets.push_back(Point(-1, -1)); // p9

    vector<Point>::iterator it;
    for(it = offsets.begin(); it < offsets.end(); ++it)
    {
        if(!((it->x < 0 && startPoint.x == 0)
            || (it->y < 0 && startPoint.y == 0)
            || (it->x > 0 && startPoint.x == mat.cols - 1)
            || (it->y > 0 && startPoint.y == mat.rows - 1)))
        {
            Point p(startPoint + *it);
            if(mat.at<uchar>(p) == 255)
                neighbors.push_back(p);
        }
    }

    return neighbors;
 }

 //this method return a vector of points from a skeleton that contains all the points 
 //  between a start point "peak" and an end point 
 //this method use the idea of Breadth first search 
  vector<Point> traceLine(Mat img , Point peak)
{
    vector<Point> vect1;
    vector<Point> vect2;
    img.at<uchar>(peak.y, peak.x)=0;//
    vect1.push_back(peak);//add peak to vect1
    while(vect1.size() != 0)
        {
        Point p=vect1[0];
        vect1.erase(vect1.begin());
        vect2.push_back(p);
        vector<Point> vectN;
        vectN = search8Neighbor(img, p);

        //cout<< " vectN.size()=" << vectN.size()<<endl;

        for(int i = 0; i < int(vectN.size()); ++i)
            {
                img.at<uchar>(vectN[i].y, vectN[i].x)=0;
                vect1.push_back(vectN[i]);
            }
        }
    return vect2;
}

int main( int argc, char** argv )
{
    cv::Mat im = cv::imread("aa.jpg",0);
    if (im.empty())
        return -1;
    cv::Mat img;
    cv::threshold(im, img, 155, 255, CV_THRESH_BINARY);
    imshow("thresholded image",im);
    vector<Point> vect1;

    Point p(3, 32);
    uchar u = img.at<uchar>(p.x, p.y);
    if(img.at<uchar>(p) == 255)
        vect1 = traceLine(img, p);

    Mat output(im.rows, im.cols, CV_8UC3, Scalar(0, 0, 0));
    vector<Point>::iterator it;

    for(it = vect1.begin(); it < vect1.end(); ++it)
    {
        Vec3b green(0, 255, 0);
        output.at<Vec3b>(*it) = green;
    }
    imshow("output", output);
    cv::waitKey();
    return 0 ;
}

这篇关于曲线/路径骨架二值图像处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆