opencv学习笔记距离变换

2022-08-12 12:07:54

距离变换cvDistTransform()
距离变换于1966年被学者首次提出,目前已被广泛应用于图像分析、计算机视觉、模式识别等领域,人们利用它来实现目标细化、骨架提取、形状插值及匹配、粘连物体的分离等。距离变换是针对二值图像的一种变换。在二维空间中,一幅二值图像可以认为仅仅包含目标和背景两种像素,目标的像素值为1,背景的像素值为0;距离变换的结果不是另一幅二值图像,而是一幅灰度级图像,即距离图像,图像中每个像素的灰度值为该像素与距其最近的背景像素间的距离。
现有的距离变换算法主要采用两类距离测度:非欧式距离和欧式距离。前者常用的有城市截取、棋盘、倒角等距离,算法采用串行扫描实现距离变换,在扫描过程中传递最短距离信息。这些算法简单快速,易于实现,但得到的仅仅是欧式距离变换(EDT)的一种近似值,在很多应用中不能满足精度要求,必须使用EDT,为此,很多学者也在研究高效快速的真实EDT算法。
定义:
void cvDistTransform
(
const CvArr* src,
CvArr* dst,
int distance_type=CV_DIST_L2,
int mask_size=3,
const float* mask=NULL
);
参数:
src
输入 8-比特、单通道 (二值) 图像. source image must be 8uC1
dst
含计算出的距离的输出图像(32-比特、浮点数、单通道). the distance map must be 32fC1
distance_type
距离类型; 可以是 CV_DIST_L1, CV_DIST_L2, CV_DIST_C 或 CV_DIST_USER.
mask_size
距离变换掩模的大小,可以是 3 或 5.
对 CV_DIST_L1 或 CV_DIST_C 的情况,参数值被强制设定为 3, 因为 3×3 mask 给出 5×5 mask 一样的结果,而且速度还更快。
mask
用户自定义距离情况下的 mask。 在 3×3 mask 下它由两个数(水平/垂直位量,对角线位移量)组成, 5×5 mask 下由三个数组成(水平/垂直位移量,对角位移和 国际象棋里的马步(马走日)) 。

函数 cvDistTransform 二值图像每一个象素点到它最邻近零象素点的距离。对零象素,函数设置 0 距离,对其它象素,它寻找由基本位移(水平、垂直、对角线或knight’s move,最后一项对 5×5 mask 有用)构成的最短路径。 全部的距离被认为是基本距离的和。由于距离函数是对称的,所有水平和垂直位移具有同样的代价 (表示为 a ), 所有的对角位移具有同样的代价 (表示为 b), 所有的 knight’s 移动具有同样的代价 (表示为 c). 对类型 CV_DIST_C 和 CV_DIST_L1,距离的计算是精确的,而类型 CV_DIST_L2 (欧式距离) 距离的计算有某些相对误差 (5×5 mask 给出更精确的结果), OpenCV 使用推荐的值:

CV_DIST_C (3×3):
a=1, b=1
CV_DIST_L1 (3×3):
a=1, b=2
CV_DIST_L2 (3×3):
a=0.955, b=1.3693
CV_DIST_L2 (5×5):
a=1, b=1.4, c=2.1969
典型的使用快速粗略距离估计 CV_DIST_L2, 3×3 mask , 如果要更精确的距离估计,使用 CV_DIST_L2, 5×5 mask。

提取手掌重心(用到距离变换)代码

#include <cv.h>
#include <highgui.h>int main()
{
    char* filename ="cs.jpg";
    IplImage* src_image = cvLoadImage(filename,1);if(!src_image)return -1;
    cvNamedWindow("src");

    CvSizesize = cvGetSize(src_image);
    IplImage* gray_image = cvCreateImage(size,8,1);
    cvCvtColor(src_image,gray_image,CV_BGR2GRAY);

    IplImage* dist_image = cvCreateImage(size,32,1);
    IplImage* bi_src = cvCreateImage(size,8,1);
    IplImage* dist8u_image = cvCreateImage(size,8,1);
    IplImage* bi_dist = cvCreateImage(size,8,1);//原图像二值化
    cvThreshold(gray_image,bi_src,100,255,CV_THRESH_BINARY);//距离变换
    cvDistTransform(bi_src,dist_image,CV_DIST_L2,3,0,0);//找最大值
    doublemax;
    cvMinMaxLoc(dist_image,0,&max,0,0);
    cvCvtScale(dist_image,dist8u_image,255./max);
    cvShowImage("dist8u_image",dist8u_image);//这一句我自己加的,显示出我们想要看到的距离变换之后的图像//对距离图像二值化,去除手指部分   cvThreshold(dist8u_image,bi_dist,80,255,CV_THRESH_BINARY);//求重心float s=0.0, x=0.0, y=0.0; 
    uchar* data = (uchar*)bi_dist->imageData;int step = bi_dist->widthStep;for(int h=0;h<bi_dist->height;h++)for(int w=0;w<bi_dist->width;w++)if(255 == data[step*h+w])
            {
                x += w;
                y += h;
                s++;
            }if(s>0)
    {
        x = x/s;
        y = y/s;
    }
    CvPoint pos = cvPoint((int)x,(int)y);

    cvCircle(src_image,pos,3,CV_RGB(255,0,0),1,CV_AA);
    cvShowImage("src",src_image);
    cvWaitKey(-1);

    cvDestroyWindow("src");
    cvReleaseImage(&src_image);
    cvReleaseImage(&gray_image);
    cvReleaseImage(&bi_src);
    cvReleaseImage(&dist8u_image);
    cvReleaseImage(&bi_dist);return0;
}

用到的图片
这里写图片描述

  • 作者:大流士一世
  • 原文链接:https://blog.csdn.net/u014751607/article/details/61919706
    更新时间:2022-08-12 12:07:54