图像处理中的距离变换_图像处理中对数变换和反向变换的区别 - CSDN
  • 图像距离变换实现了像素与图像区域的距离变换,使得最后生成的图像在该自己元素位置处的像素为0,临近的背景的像素具有较小的值,且随着距离的增大它的的数值也就越大。对于距离图像来说,图像中的每个像素的灰度...

    版权声明:本文为博主转载文章,如有不妥,请私信删除。原文地址: https://blog.csdn.net/qq_34784753/article/details/68951918

    图像的距离变换实现了像素与图像区域的距离变换,使得最后生成的图像在该自己元素位置处的像素为0,临近的背景的像素具有较小的值,且随着距离的增大它的的数值也就越大。对于距离图像来说,图像中的每个像素的灰度值为该像素与距离其最近的背景像素间的距离,也就是说,给每个像素赋值为离它最近的背景像素点与其距离,一幅二值图像的距离变换可以提供每个像素到最近的非零像素的距离。

    距离变换的一般步骤如下:

    1.将输入图片转换为二值图像,前景设置为1,背景设置为0;

    2.第一遍水平扫描从左上角开始,依次从左往右逐行扫描,扫描完一行自动跳转到下一行的最左端继续扫描,按行遍历图像。掩膜模板mask为maskL 使用下面的公式进行计算。

    其中D表示距离,包括欧氏距离,棋盘距离或是麦哈顿距离,f(p)为像素点p的像素值。

    3.第二遍水平扫描从右下角开始,依次从右往左逐行扫描,扫描完一行自动转到上一行的最右端继续扫描,按行遍历图像,掩膜模板mask为maskR,方法和上一步相同

    4.根据模板maskL和maskR的扫描结果得到最终的距离变换图像。

    具体的程序

    1.  

      //距离变换的扫描实现
      
      
      #include <iostream>
      
      #include <opencv2\core\core.hpp>
      
      #include <opencv2\highgui\highgui.hpp>
      
      #include <opencv2\imgproc\imgproc.hpp>
      
      
      using namespace cv;
      
      using namespace std;
      
      
      //计算欧氏距离的函数
      
      float calcEuclideanDiatance(int x1, int y1, int x2, int y2)
      
      {
      
      return sqrt(float((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)));
      
      }
      
      
      //计算棋盘距离的函数
      
      int calcChessboardDistance(int x1, int y1, int x2, int y2)
      
      {
      
      return cv::max(abs(x1 - x2), (y1 - y2));
      
      }
      
      
      //计算麦哈顿距离(街区距离)
      
      int calcBlockDistance(int x1, int y1, int x2, int y2)
      
      {
      
      return abs(x1 - x2) + abs(y1 - y2);
      
      }
      
      
      //距离变换函数的实现
      
      void distanceTrans(Mat &srcImage, Mat &dstImage)
      
      {
      
      CV_Assert(srcImage.data != nullptr);
      
      //CV_Assert()若括号中的表达式值为false,则返回一个错误信息。
      
      //定义灰度图像的二值图像
      
      Mat grayImage, binaryImage;
      
      //将原图像转换为灰度图像
      
      cvtColor(srcImage, grayImage, CV_BGR2GRAY);
      
      //将灰度图像转换为二值图像
      
      threshold(grayImage, binaryImage, 100, 255, THRESH_BINARY);
      
      imshow("二值化图像", binaryImage);
      
      
      int rows = binaryImage.rows;
      
      int cols = binaryImage.cols;
      
      uchar *pDataOne;
      
      uchar *pDataTwo;
      
      float disPara = 0;
      
      float fDisMIn = 0;
      
      
      //第一遍遍历图像,使用左模板更新像素值
      
      for (int i = 1; i < rows - 1; i++)
      
      {
      
      //图像的行指针的获取
      
      pDataOne = binaryImage.ptr<uchar>(i);
      
      for (int j = 1; j < cols; j++)
      
      {
      
      //分别计算左模板掩码的相关距离
      
      //PL PL
      
      //PL P
      
      //PL
      
      pDataTwo = binaryImage.ptr<uchar>(i - 1);
      
      disPara = calcEuclideanDiatance(i, j, i - 1, j - 1);
      
      fDisMIn = cv::min((float)pDataOne[j], disPara + pDataTwo[j - 1]);
      
      disPara = calcEuclideanDiatance(i, j, i - 1, j);
      
      fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j]);
      
      pDataTwo = binaryImage.ptr<uchar>(i);
      
      disPara = calcEuclideanDiatance(i, j, i, j - 1);
      
      fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j-1]);
      
      pDataTwo = binaryImage.ptr<uchar>(i+1);
      
      disPara = calcEuclideanDiatance(i, j, i+1,j-1);
      
      fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j - 1]);
      
      pDataOne[j] = (uchar)cvRound(fDisMIn);
      
      }
      
      }
      
      
      //第二遍遍历图像,使用右模板更新像素值
      
      for (int i = rows - 2; i > 0; i--)
      
      {
      
      pDataOne = binaryImage.ptr<uchar>(i);
      
      for (int j = cols - 1; j >= 0; j--)
      
      {
      
      //分别计算右模板掩码的相关距离
      
      //pR pR
      
      //pR p
      
      //pR
      
      pDataTwo = binaryImage.ptr<uchar>(i + 1);
      
      disPara = calcEuclideanDiatance(i, j, i + 1, j);
      
      fDisMIn = cv::min((float)pDataOne[j], disPara + pDataTwo[j]);
      
      disPara = calcEuclideanDiatance(i, j, i + 1, j + 1);
      
      
      fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j+1]);
      
      pDataTwo = binaryImage.ptr<uchar>(i);
      
      disPara = calcEuclideanDiatance(i, j, i, j +1);
      
      fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j + 1]);
      
      pDataTwo = binaryImage.ptr<uchar>(i - 1);
      
      disPara = calcEuclideanDiatance(i, j, i - 1, j + 1);
      
      fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j + 1]);
      
      pDataOne[j] = (uchar)cvRound(fDisMIn);
      
      }
      
      }
      
      dstImage = binaryImage.clone();
      
      }
      
      
      //主函数
      
      int main()
      
      {
      
      Mat srcImage = imread("2345.jpg");
      
      if (!srcImage.data)
      
      {
      
      cout << "读入图片错误!" << endl;
      
      system("pause");
      
      return -1;
      
      }
      
      Mat dstImage;
      
      distanceTrans(srcImage, dstImage);
      
      imshow("距离变换图像", dstImage);
      
      waitKey();
      
      return 0;
      
      }

       

    这里使用的是以计算欧氏距离为例,执行程序后的结果如下:

     

    在OpenCV中也提供了相关的函数

    函数distanceTransform函数用来计算原图像中每个像素的距离,函数的声明如下:

    CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray src,
    
    OutputArray dst, OutputArray labels, int distanceType, int maskSize,int labelType=DIST_LABEL_CCOMP );
    
    //! computes the distance transform map
    
    CV_EXPORTS_W void distanceTransform( InputArray src, OutputArray dst, int distanceType, int maskSize );
    
    

    函数说明

    用于计算图像中每一个非零点距离离自己最近的零点的距离,distanceTransform的第二个Mat矩阵参数dst保存了每一个点与最近的零点的距离信息,图像上越亮的点,代表了离零点的距离越远。

    第一个参数src是单通道的8bit的二值图像(只有0或1)

    第二个参数dst表示的是计算距离的输出图像,可以使单通道32bit浮点数据

    第三个参数distanceType表示的是选取距离的类型,可以设置为CV_DIST_L1,CV_DIST_L2,CV_DIST_C等,具体如下:

    DIST_USER = ⑴, //!< User defineddistance
    
    DIST_L1 = 1, //!< distance = |x1-x2| + |y1-y2|
    
    DIST_L2 = 2, //!< the simple euclidean distance
    
    DIST_C = 3, //!< distance = max(|x1-x2|,|y1-y2|)
    
    DIST_L12 = 4, //!< L1-L2 metric: distance =2(sqrt(1+x*x/2) - 1))
    
    DIST_FAIR = 5, //!< distance = c^2(|x|/c-log(1+|x|/c)),c = 1.3998
    
    DIST_WELSCH = 6, //!< distance = c^2/2(1-exp(-(x/c)^2)), c= 2.9846
    
    DIST_HUBER = 7 //!< distance = |x|<c ? x^2/2 :c(|x|-c/2), c=1.345
    
    

    第四个参数maskSize表示的是距离变换的掩膜模板,可以设置为3,5或CV_DIST_MASK_PRECISE,对 CV_DIST_L1 或CV_DIST_C 的情况,参数值被强制设定为 3, 因为3×3 mask 给出5×5 mask 一样的结果,而且速度还更快。 

    参数labels表示可选输出2维数组

    参数labelType表示的是输出二维数组的类型

    函数的具体用法如下程序所示:

    //使用OpenCV中的相应的函数实现距离变换
    
    
    #include <iostream>
    
    #include <opencv2\core\core.hpp>
    
    #include <opencv2\highgui\highgui.hpp>
    
    #include <opencv2\imgproc\imgproc.hpp>
    
    
    using namespace cv;
    
    using namespace std;
    
    
    int main()
    
    {
    
    Mat srcImage = imread("2345.jpg");
    
    if (!srcImage.data)
    
    {
    
    cout << "读入图片错误!" << endl;
    
    system("pause");
    
    return -1;
    
    }
    
    //转换为灰度图像
    
    Mat grayImage;
    
    cvtColor(srcImage, grayImage, CV_BGR2GRAY);
    
    //转换为二值图像
    
    Mat binaryImage;
    
    threshold(grayImage, binaryImage, 100, 255, THRESH_BINARY);
    
    //距离变换
    
    Mat dstImage;
    
    distanceTransform(binaryImage, dstImage, CV_DIST_L2, CV_DIST_MASK_PRECISE);
    
    //使用欧式距离进行计算
    
    //归一化矩阵
    
    normalize(dstImage, dstImage, 0, 1, NORM_MINMAX);
    
    imshow("二值化图像", binaryImage);
    
    imshow("距离变换后的图像", dstImage);
    
    waitKey();
    
    return 0;
    
    }
    
    

    程序执行后,执行的结果如下:

     

     

    --------------------- 本文来自 S大幕 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/qq_34784753/article/details/68951918?utm_source=copy

    展开全文
  • 图像处理距离变换

    万次阅读 2013-05-15 21:43:50
    距离变换是二值图像处理与操作常用手段,在骨架提取,图像窄化中常有应用。距离 变换的结果是得到一张与输入图像类似的灰度图像,但是灰度值只出现在前景区域。并 且越远离背景边缘的像素灰度值越大。 基本思想...

    图像处理之距离变换

    概述

    距离变换是二值图像处理与操作中常用手段,在骨架提取,图像窄化中常有应用。距离

    变换的结果是得到一张与输入图像类似的灰度图像,但是灰度值只出现在前景区域。并

    且越远离背景边缘的像素灰度值越大。

    基本思想

    根据度量距离的方法不同,距离变换有几种不同的方法,假设像素点p1(x1, y1), 

    p2(x2, y2)计算距离的方法常见的有:

    1.      欧几里德距离,Distance =

    2.      曼哈顿距离(City Block Distance),公式如下:Distance = |x2-x1|+|y2-y1|

    3.      象棋格距离(Chessboard Distance),公式如下:Distance = max(|x2-x1|,|y2-y1|)

    一旦距离度量公式选择,就可以在二值图像的距离变换中使用。一个最常见的距离变换

    算法就是通过连续的腐蚀操作来实现,腐蚀操作的停止条件是所有前景像素都被完全

    腐蚀。这样根据腐蚀的先后顺序,我们就得到各个前景像素点到前景中心骨架像素点的

    距离。根据各个像素点的距离值,设置为不同的灰度值。这样就完成了二值图像的距离

    变换。

    注意点:

    腐蚀操作结构体的选取会影响距离变换的效果,例子使用3*3的矩阵完成。有很多快速

    的距离变换算法,感兴趣的可以自己研究。

    运行结果:


    关键代码解析:

    初始化二值图像,读取像素,获取前景边缘像素与背景边缘像素

    	public DistanceTransform(float scaleValue, float offsetValue, BufferedImage src)
    	{
    		this.scaleValue = scaleValue;
    		this.offsetValue = offsetValue;
    		this.inputImage = src;
    		this.width = src.getWidth();
    		this.height = src.getHeight();
            int[] inPixels = new int[width*height];
            getRGB( src, 0, 0, width, height, inPixels );
            int index = 0;
            pixels2D = new int[height][width]; // row, column
            greyLevel = new int[height][width];
            for(int row=0; row < height; row++)
            {
            	for(int col=0; col<width; col++) 
            	{
            		index = row * width + col;
            		int grayValue = (inPixels[index] >> 16) & 0xff;
            		pixels2D[row][col] = grayValue;
            		greyLevel[row][col] = 0;
            	}
            }
            
            generateForegroundEdge();
            generateBackgroundEdgeFromForegroundEdge();
            
    	}
    现实距离变换的代码如下:

    @Override
    public BufferedImage filter(BufferedImage src, BufferedImage dest) {
    	
    	// calculate the distance here!!
    	int index = 1;
        while (foregroundEdgePixels.size() > 0) {
        	distanceSingleIteration(index);
            ++index;
        }
        
        // loop the each pixel and assign the color value according to distance value
    	for (int row = 0; row < inputImage.getHeight(); row++) {
    	      for (int col = 0; col < inputImage.getWidth(); col++) {
    	    	  if(greyLevel[row][col] > 0) {
    		    	  int colorValue = (int)Math.round(greyLevel[row][col] * scaleValue + offsetValue);
    		    	  colorValue = colorValue > 255 ? 255 : ((colorValue < 0) ? 0 : colorValue);
    		    	  this.pixels2D[row][col] = colorValue;
    	    	  }
    	    	  
    	      }
    	}
    	
    	// build the result pixel data at here !!!
        if ( dest == null )
            dest = createCompatibleDestImage(inputImage, null );
        
        index = 0;
        int[] outPixels = new int[width*height];
        for(int row=0; row<height; row++) {
        	int ta = 0, tr = 0, tg = 0, tb = 0;
        	for(int col=0; col<width; col++) {
        		if(row == 75 && col > 60) {
        			System.out.println("ddddd");
        		}
        		index = row * width + col;
        		tr = tg = tb = this.pixels2D[row][col];
        		ta = 255;
        		outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
        	}
        }
        setRGB( dest, 0, 0, width, height, outPixels );
    	return dest;
    }
    生成前景边缘像素与背景边缘像素的代码如下:

      private void generateForegroundEdge()
      {
        foregroundEdgePixels.clear();
    
        for (int row = 0; row < height; row++)
          for (int col = 0; col < width; col++)
            if (this.pixels2D[row][col] == foreground) {
              Point localPoint = new Point(col, row);
              for (int k = -1; k < 2; ++k) // 3*3 matrix
            	  for (int l = -1; l < 2; ++l) {
                  if ((localPoint.x + l < 0) || (localPoint.x + l >= this.width) || (localPoint.y + k < 0) || (localPoint.y + k >= this.height) || 
                    (this.pixels2D[(localPoint.y + k)][(localPoint.x + l)] != background) || (this.foregroundEdgePixels.contains(localPoint)))
                    continue;
                  this.foregroundEdgePixels.add(localPoint);
                }
            }
      }
      
      private void generateBackgroundEdgeFromForegroundEdge()
      {
        this.backgroundEdgePixels.clear();
    
        Iterator<Point> localIterator = this.foregroundEdgePixels.iterator();
        while (localIterator.hasNext()) {
          Point localPoint1 = new Point((Point)localIterator.next());
          for (int i = -1; i < 2; ++i)
            for (int j = -1; j < 2; ++j)
              if ((localPoint1.x + j >= 0) && (localPoint1.x + j < this.width) && (localPoint1.y + i >= 0) && (localPoint1.y + i < this.height)) {
                Point localPoint2 = new Point(localPoint1.x + j, localPoint1.y + i);
                if (this.pixels2D[localPoint2.y][localPoint2.x] == background)
                  this.backgroundEdgePixels.add(localPoint2);
              }
        }
      }

    展开全文
  • 数字图像距离变换算法

    千次阅读 2018-12-02 10:30:57
    数字图像距离变换算法一、图像数字化二、距离三、距离变换四、OpenCV代码实现 一、图像数字化 通过传感器获得的图像是平面坐标(x,y)的连续函数f(x,y),它的值图像对应位置的亮度。为了能够让计算机来处理,需要...

    在这里插入图片描述

    一、图像数字化

    通过传感器获得的图像是平面坐标(x,y)的连续函数f(x,y),它的值图像对应位置的亮度。为了能够让计算机来处理,需要对图像进行采样,并且对亮度值进行量化。

    1、采样。对连续函数f(x,y)进行采样,就是分别对x轴和y轴,按照固定间隔取值,得到平面坐标上的M×N个点,将其函数值作为元素生成M行N列的矩阵。

    2、量化亮度值。将f(x,y)的值转化为等价的整数值的过程称为量化,量化的级别越高,图像越细致。通常将亮度值表示为0-255之间的整数。

    这样,在计算机中通常以矩阵表示数字图像,矩阵的元素对应图像的亮度信息。

    二、距离

    满足以下三个条件的函数DD称作距离:
    (1)同一性:D(p,q)0p=qD(p,q)=0D(p,q)\ge 0。 当且仅当p=q时,D(p,q)=0。

    (2)对称性:D(p,q)=D(q,p)D(p,q)=D(q,p)。

    (3)三角不等式:D(p,r)D(p,q)+D(q,r)D(p,r)\le D(p,q)+D(q,r)。

    数字图像的距离有多种定义方式,包括欧式距离、城市街区距离、棋盘距离等。以下以两坐标点a=(i,j)a=(i,j)b=(k,l)b=(k,l)的距离为例,来说明各种距离的定义方式。

    欧式距离De{D_e}就是通常所说的距离,它定义为
    De(a,b)=((ik)2)+(jl)2D_e(a,b)=\sqrt{((i-k)^2)+(j-l)^2}

    欧式距离在事实上比较直观,但是平方根计算比较费时,且距离可能不是数。

    城市街区距离D4D_4,它定义为在只允许横向和纵向运动的情况下,从起点到终点的移动步数。用公式表示为
    D4(a,b)=ik+jlD_4(a,b)=|i-k|+|j-l|

    符号D4D_4中的44表示在这种定义下,像素点是44邻接的,即每个点只与它的上、下、左、右相邻的44个点之间的距离为11

    如果允许横向、纵向和沿对角线方向移动,则可以得到棋盘距离D8D_8的定义
    D8(a,b)=max{ik,jl}D_8(a,b)=max\{|i-k|,|j-l|\}

    符号D8D_8中的88表示在这种定义下,像素点是88邻接的,即每个点只与它的上、下、左、右、四个对角线方向相邻的88个点之间的距离为11

    显然,以上三种距离的定义都满足距离的定义条件。

    三、距离变换

    距离变换也叫作距离函数或者斜切算法。它是距离概念的一个应用,图像处理的一些算法以距离变换为基础。距离变换描述的是图像中像素点与某个区域块的距离,区域块中的像素点值为0,临近区域块的像素点有较小的值,离它越远值越大。

    以二值图像为例,其中区域块内部的像素值为1,其他像素值为0。距离变换给出每个像素点到最近的区域块边界的距离,区域块内部的距离变换结果为0。输入图像如图1所示,D4距离的距离变换结果如图2所示。

    下面来讨论距离变换算法,其核心是利用两个小的局部掩膜遍历图像。第一遍利用掩模1,左上角开始,从左往右,从上往下。第二遍利用第二个掩模,右下角开始,从右往左,从下往上。掩模形状如下图所示:

    按照某种距离(如:D4D_4距离或D8D_8距离)对大小为M×NM×N的图像中的区域块作距离变换,算法过程如下:

    1、建立一个大小为M×NM×N的数组FF,作如下的初始化:将区域块中的元素设置为00,其余元素设置为无穷;

    2、利用掩模1(mask1),左上角开始,从左往右,从上往下遍历数组,将掩模中P点对应的元素的值作如下更新:
    F(P)=minqmask1{F(P),D(P,q)+F(q)}F(P)=\underset{{q\in mask1}}{min}\{F(P),D(P,q)+F(q)\}

    3、利用掩模2(mask2),右下角开始,从右往左,从下往上遍历数组,将掩模中P点对应的元素的值作如下更新:
    F(P)=minqmask2{F(P),D(P,q)+F(q)}F(P)=\underset{{q\in mask2}}{min}\{F(P),D(P,q)+F(q)\}

    最终得到的更新后的数组即为距离变换的结果。

    这个算法过程在图像编边界需要做出调整,因为在边界处,掩模不能全部覆盖图像,这时可以将掩模中没有对应元素的位置的值当作0来处理。

    四、OpenCV代码实现

    这个算法过程经过很多的改进,但基本原理并没有区别。开源计算机视觉库OpenCV中,距离变换算法有相应的实现,声明如下:

    CV_EXPORTS_W void distanceTransform( InputArray src, OutputArray dst,
                                         int distanceType, int maskSize, int dstType=CV_32F);
    

    参数详解:

    • InputArray src:输入图像,一般为二值图像;
    • OutputArray dst:输出的图像,距离变换结果;
    • int distanceType:用于距离变换的距离类型(欧氏距离:DIST_L2 = 2;D4D_4距离:DIST_L1 = 1;D8D_8距离:DIST_C = 3等);
    • int mask_size:距离变换掩模的大小,一般为3或5;
    • int dstType:输出图像的数据类型,可以为CV_8U或CV_32F。

    下面我们用一个具体的例子来展示距离变换的效果。将大小为480×480480\times480,其中有三个像素点设置为1,其余都为0的一张图片作为输入图像,分别在欧式距离、D4D_4距离和D8D_8距离下,距离变换的结果。

    效果如下图所示:

    下面是代码实现:

    #include<opencv2/opencv.hpp>
    using namespace cv;
    using namespace std;
    
    int main()
    {
        //初始化输入图像和变换结果图像
        Mat mat(480, 480, CV_8UC1, Scalar(0)), transMatE, transMatD4, transMatD8;
    
        //给输入图像指定三个像素点作为距离变换原点(区域块)
        mat.at<uchar>(100, 200) = 1;
        mat.at<uchar>(200, 100) = 1;
        mat.at<uchar>(300, 300) = 1;
    
        //将将输入图像中1和0调换,使得原点距离为0
        mat = 1 - mat;
    
        //显示原始图像(显示为黑色)
        imshow("原始图片", mat);
    
        //分别利用欧式距离、D4距离和D8距离作距离变换,将结果存入transMatD4、transMatD8和transMatE
        distanceTransform(mat, transMatE, DIST_L2, 0);
        distanceTransform(mat, transMatD4, DIST_L1, 0, CV_8U);
        distanceTransform(mat, transMatD8, DIST_C, 0);
    
        //欧式距离与D8距离作变换后,值为32位浮点数,以下代码将其值转为uchar类型
        transMatE.convertTo(transMatE, CV_8U);
        transMatD8.convertTo(transMatD8, CV_8U);
    
        //显示距离变换结果
        imshow("欧式距离变换后的图片", transMatE);
        imshow("D4距离变换后的图片", transMatD4);
        imshow("D8距离变换后的图片", transMatD8);
    
    
        waitKey();
    
        return 0;
    
    展开全文
  • 对于距离图像来说,图像中的每个像素的灰度值为该像素与距离其最近的背景像素间的距离,也就是说,给每个像素赋值为离它最近的背景像素点与其距离,一幅二值图像距离变换可以提供每个像素到最近的非零像素的距离 ...

    图像的距离变换实现了像素与图像区域的距离变换,使得最后生成的图像在该自己元素位置处的像素为0,临近的背景的像素具有较小的值,且随着距离的增大它的的数值也就越大。
    对于距离图像来说,图像中的每个像素的灰度值为该像素与距离其最近的背景像素间的距离,也就是说,给每个像素赋值为离它最近的背景像素点与其距离,一幅二值图像的距离变换可以提供每个像素到最近的非零像素的距离

    根据度量距离的方法不同,距离变换有几种不同的方法,假设像素点为p1(x1, y1),p2(x2, y2),计算距离的方法常见的有:

    • 1.欧几里德距离
    • 2.曼哈顿距离(City Block Distance)
      Distance = |x2-x1|+|y2-y1|
    • 3.象棋格距离(Chessboard Distance)
      Distance = max(|x2-x1|,|y2-y1|)

    而这个方法在官方网站上有可以直接使用的方法,于是我就用官网的方法来试了一下,结果如下:
    在这里插入图片描述
    这里要注意需要转为灰度图才可以进行下面的操作。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    上面的滑动条调节的是图片亮度,随着图片亮度增大,打火机的轮廓变得模糊,而原来没有出现的白色圆盒的轮廓开始出现。

    图像距离算法还可以应用于目标细化,骨架提取,粘连物体的分离等,并不仅仅是表示出图像中目标与背景的距离。


    同时也欢迎各位关注我的微信公众号 南木的下午茶

    在这里插入图片描述


    代码自取:

    // CVE6.2.cpp: 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdio.h>
    
    using namespace cv;
    
    int maskSize0 = CV_DIST_MASK_5;
    int voronoiType = -1;
    int edgeThresh = 100;
    int distType0 = CV_DIST_L1;
    
    // The output and temporary images
    Mat gray;
    
    // threshold trackbar callback
    static void onTrackbar(int, void*)
    {
    	static const Scalar colors[] =
    	{
    		Scalar(0,0,0),
    		Scalar(255,0,0),
    		Scalar(255,128,0),
    		Scalar(255,255,0),
    		Scalar(0,255,0),
    		Scalar(0,128,255),
    		Scalar(0,255,255),
    		Scalar(0,0,255),
    		Scalar(255,0,255)
    	};
    
    	int maskSize = voronoiType >= 0 ? CV_DIST_MASK_5 : maskSize0;
    	int distType = voronoiType >= 0 ? CV_DIST_L2 : distType0;
    
    	Mat edge = gray >= edgeThresh, dist, labels, dist8u;
    
    	if (voronoiType < 0)
    		distanceTransform(edge, dist, distType, maskSize);
    	else
    		distanceTransform(edge, dist, labels, distType, maskSize, voronoiType);
    
    	if (voronoiType < 0)
    	{
    		// begin "painting" the distance transform result
    		dist *= 5000;
    		pow(dist, 0.5, dist);
    
    		Mat dist32s, dist8u1, dist8u2;
    
    		dist.convertTo(dist32s, CV_32S, 1, 0.5);
    		dist32s &= Scalar::all(255);
    
    		dist32s.convertTo(dist8u1, CV_8U, 1, 0);
    		dist32s *= -1;
    
    		dist32s += Scalar::all(255);
    		dist32s.convertTo(dist8u2, CV_8U);
    
    		Mat planes[] = { dist8u1, dist8u2, dist8u2 };
    		merge(planes, 3, dist8u);
    	}
    	else
    	{
    		dist8u.create(labels.size(), CV_8UC3);
    		for (int i = 0; i < labels.rows; i++)
    		{
    			const int* ll = (const int*)labels.ptr(i);
    			const float* dd = (const float*)dist.ptr(i);
    			uchar* d = (uchar*)dist8u.ptr(i);
    			for (int j = 0; j < labels.cols; j++)
    			{
    				int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j] - 1) % 8 + 1;
    				float scale = 1.f / (1 + dd[j] * dd[j] * 0.0004f);
    				int b = cvRound(colors[idx][0] * scale);
    				int g = cvRound(colors[idx][1] * scale);
    				int r = cvRound(colors[idx][2] * scale);
    				d[j * 3] = (uchar)b;
    				d[j * 3 + 1] = (uchar)g;
    				d[j * 3 + 2] = (uchar)r;
    			}
    		}
    	}
    
    	imshow("Distance Map", dist8u);
    }
    
    static void help()
    {
    	printf("\nProgram to demonstrate the use of the distance transform function between edge images.\n"
    		"Usage:\n"
    		"./distrans [image_name -- default image is stuff.jpg]\n"
    		"\nHot keys: \n"
    		"\tESC - quit the program\n"
    		"\tC - use C/Inf metric\n"
    		"\tL1 - use L1 metric\n"
    		"\tL2 - use L2 metric\n"
    		"\t3 - use 3x3 mask\n"
    		"\t5 - use 5x5 mask\n"
    		"\t0 - use precise distance transform\n"
    		"\tv - switch to Voronoi diagram mode\n"
    		"\tp - switch to pixel-based Voronoi diagram mode\n"
    		"\tSPACE - loop through all the modes\n\n");
    }
    
    const char* keys =
    {
    	"{1| |stuff.jpg|input image file}"
    };
    
    int main(int argc, const char** argv)
    {
    	help();
    	CommandLineParser parser(argc, argv, keys);
    	//string filename = parser.get<string>("1");
    	//gray = imread("stuff.jpg", 0);
    	cv::Mat img = imread("E:/C++/CVE6.2/图片1.png");
    	imshow("原图", img);
    	gray = imread("E:/C++/CVE6.2/图片1.png", 0);
    	imshow("灰度图", gray);
    	resize(gray, gray, Size(), 0.25, 0.25, 1);
    	//if (gray.empty())
    	//{
    	//	printf("Cannot read image file: %s\n", filename.c_str());
    	//	help();
    	//	return -1;
    	//}
    
    	namedWindow("Distance Map", CV_WINDOW_NORMAL);
    	createTrackbar("Brightness Threshold", "Distance Map", &edgeThresh, 255, onTrackbar, 0);
    
    	for (;;)
    	{
    		// Call to update the view
    		onTrackbar(0, 0);
    
    		int c = waitKey(0) & 255;
    
    		if (c == 27)
    			break;
    
    		if (c == 'c' || c == 'C' || c == '1' || c == '2' ||
    			c == '3' || c == '5' || c == '0')
    			voronoiType = -1;
    
    		if (c == 'c' || c == 'C')
    			distType0 = CV_DIST_C;
    		else if (c == '1')
    			distType0 = CV_DIST_L1;
    		else if (c == '2')
    			distType0 = CV_DIST_L2;
    		else if (c == '3')
    			maskSize0 = CV_DIST_MASK_3;
    		else if (c == '5')
    			maskSize0 = CV_DIST_MASK_5;
    		else if (c == '0')
    			maskSize0 = CV_DIST_MASK_PRECISE;
    		else if (c == 'v')
    			voronoiType = 0;
    		else if (c == 'p')
    			voronoiType = 1;
    		else if (c == ' ')
    		{
    			if (voronoiType == 0)
    				voronoiType = 1;
    			else if (voronoiType == 1)
    			{
    				voronoiType = -1;
    				maskSize0 = CV_DIST_MASK_3;
    				distType0 = CV_DIST_C;
    			}
    			else if (distType0 == CV_DIST_C)
    				distType0 = CV_DIST_L1;
    			else if (distType0 == CV_DIST_L1)
    				distType0 = CV_DIST_L2;
    			else if (maskSize0 == CV_DIST_MASK_3)
    				maskSize0 = CV_DIST_MASK_5;
    			else if (maskSize0 == CV_DIST_MASK_5)
    				maskSize0 = CV_DIST_MASK_PRECISE;
    			else if (maskSize0 == CV_DIST_MASK_PRECISE)
    				voronoiType = 0;
    		}
    	}
    
    	return 0;
    }
    
    
    
    
    展开全文
  • 距离变换处理图像通常都是二值图像,而二值图像其实就是把图像分为两部分,即背景和物体两部分,物体通常又称为前景目标!通常我们把前景目标的灰度值设为255,即白色,背景的灰度值设为0,即黑色。所以定义的.....
  •  这篇文章的主要目的是通过建立一维傅里叶变换与图像傅里叶变换中相关概念的对应关系来帮助读者理解图像处理中的离散傅里叶变换,因此,理解图像中离散傅里叶变换的前提条件是读者需要了解一维傅里叶变换的基本知识...
  • 图像匹配之距离变换匹配法

    千次阅读 2017-08-03 09:38:45
    距离变换是一种常见的二值图像处理算法,用来计算图像任意位置到最近边缘点的距离,常见的距离测度函数有切削距离,街区距离和欧式距。切削距离和街区距离是欧式距离的一种近似。 基于距离变换
  • 图像处理之倒角距离变换

    万次阅读 2015-01-11 23:07:50
    介绍二值图像倒角距离变换算法,帮助读者理解图像倒角距离变换分步骤实现!
  • 图像距离变换与应用

    千次阅读 2016-11-25 15:31:07
    1、象素间各种距离的定义及计算 我们知道,构成一幅数字图像最基本的元素是一个一个的像素点,也就是像素。理解像素间的一些基本关系是我们以后进行图形图形处理的基础和关键。如相邻像素(像素的邻域),像素的...
  • 图像处理之霍夫变换(直线检测算法)

    万次阅读 多人点赞 2016-11-01 20:35:59
    图像处理之霍夫变换(直线检测算法) 霍夫变换是图像变换中的经典手段之一,主要用来从图像中分离出具有某种相同特征的几何 形状(如,直线,圆等)。霍夫变换寻找直线与圆的方法相比与其它方法可以更好的减少噪 声...
  • 图像处理中距离含义

    千次阅读 2019-06-28 10:40:42
    距离变换是二值图像处理与操作常用手段,在骨架提取,图像窄化中常有应用。距离 变换的结果是得到一张与输入图像类似的灰度图像,但是灰度值只出现在前景区域。并 且越远离背景边缘的像素灰度值越大。 根据度量...
  • 数字图像处理:图像变换的基本模型 一、常用图象的变换模型 变换模型是指根据待匹配图像与背景图像之间几何畸变的情况,所选择的能最佳拟合两幅图像之间变化的几何变换模型。可采用的变换模型有如下几种:刚性变换、...
  • 图像的频率是表征图像中灰度变化剧烈程度的指标,是灰度在平面空间上的梯度。如:大面积的沙漠在图像中是一片灰度变化缓慢的区域,对应的频率值很低;而对于地表属性变换剧烈的边缘区域在图像中是一片灰度变化剧烈的...
  • 前言  前面转载过一篇关于傅里叶变换原理的文章《一篇难得的关于傅里叶分析的好文》。那篇文章写得非常棒,浅显易懂,可以说稍有基础的人...那么在数字图像处理中,傅里叶变换之后得到的频谱图又有怎样的运用呢?...
  • 二值图像距离变换研究

    千次阅读 2017-12-29 14:17:21
    二值图像距离变换的概念由Rosenfeld和Pfaltz于1966年在论文[1]提出,目前广泛应用于计算机图形学,目标识别及GIS空间分析等领域,其主要思想是通过表识空间点(目标点与背景点)距离的过程,最终将二值图像
  • 图像分割是图像处理最重要的处理手段之一 图像分割的目标是将图像像素根据一定的规则分为若干个cluster集合每个集合包括一类像素 根据算法分为监督学习和无监督学习,图像分割的算法多数都是无监督学习-KMenas ...
  • 图像处理之基于采样距离变换算法

    千次阅读 2013-12-30 22:50:46
    基于采样函数的二值图像距离变换算法!可以扩展到3D应用。
  • 图像快速处理算法II 距离变换

    千次阅读 2012-07-31 12:57:13
    距离变换图像处理中匹配的一个基础算法。国外有人对此算法进行了详细的研究和总结。并列出了很多快速算法,进行分析比较。个人认为这种基础性质的东西真是很重要。虽然大家都清楚距离变换是个啥意思,就像我上一篇...
  •  距离变换(distance transform,DT)在图像处理、计算机视觉等领域有非常多的运用,例如骨架化、目标细化、黏连目标分离等。在Matlab和OpenCV中都有进行距离变换的函数。Matlab有bwdist函数用于二值化图像的距离...
  • 二值图像距离变换的概念由Rosenfeld和Pfaltz于1966年在论文提出,其主要思想是通过表识空间点(目标点与背景点)距离的过程,最终将二值图像转换为灰度图像。变换的结果是得到一张与输入图像类似的灰度图像,但是...
1 2 3 4 5 ... 20
收藏数 35,148
精华内容 14,059
关键字:

图像处理中的距离变换