2019-06-28 10:37:13 zhouzongzong 阅读数 535

距离变换是二值图像处理与操作中常用手段,在骨架提取,图像窄化中常有应用。距离变换的结果是得到一张与输入图像类似的灰度图像,但是灰度值只出现在前景区域。并且越远离背景边缘的像素灰度值越大。

根据度量距离的方法不同,距离变换有几种不同的方法,假设像素点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|)
    在这里插入图片描述

一旦距离度量公式选择,就可以在二值图像的距离变换中使用。一个最常见的距离变换算法就是通过连续的腐蚀操作来实现,腐蚀操作的停止条件是所有前景像素都被完全腐蚀这样根据腐蚀的先后顺序,我们就得到各个前景像素点到前景中心骨架像素点的距离。根据各个像素点的距离值,设置为不同的灰度值。这样就完成了二值图像的距离

2016-04-12 21:22:40 jaych 阅读数 8664

本篇文章主要描述颜色距离及其具体颜色距离的实现。

1、颜色距离

颜色距离指的是两个颜色之间的差距,通常距离越大,两个颜色相差越大,反之,两个颜色越相近。在计算颜色距离时,有类似计算两点间欧式距离的公式一样,在RGB空间内,可以得到两个颜色之间的距离为:


这里写图片描述

其中,C1 C2表示颜色1和颜色2,C1R表示颜色1的R通道。
但是,由于RGB空间是线性的并且相互正交,而人眼的视觉系统并不是线性的,RGB空间并不能反映人眼对颜色的感知,相对应的颜色距离也不能很好的反映两个颜色是否相近。

针对这个问题,于是有了LAB颜色空间,及其对应的色差计算。

2、LAB颜色空间及色差计算

LAB颜色空间是基于人眼对颜色的感知,可以表示人眼所能感受到的所有颜色。L表示明度,A表示红绿色差,B表示蓝黄色差。两个颜色之见的色差:


这里写图片描述

ΔE 表示色差,ΔL/Δa/Δb分别表示两个颜色之间在不同分量的差值。

为了简化计算及保证计算效果,有人在RGB空间上通过公式计算出加权的欧式距离。

3、改进的加权欧式距离

以下为具体的计算方法,详细说明可以参考:链接


这里写图片描述

具体的C代码如下:

typedef struct {
   unsigned char r, g, b;
} RGB;

double ColourDistance(RGB e1, RGB e2)
{
  long rmean = ( (long)e1.r + (long)e2.r ) / 2;
  long r = (long)e1.r - (long)e2.r;
  long g = (long)e1.g - (long)e2.g;
  long b = (long)e1.b - (long)e2.b;
  return sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}
2019-09-02 11:15:30 weixin_41887615 阅读数 68

距离变换

原理:以后再写,有疑问的可以去网上找相关理论,或者在下面留言

代码:

距离变换

  • QImage &image 输入图像
  • QImage &otpImage 输出图像
  • int distant_modle 距离计算模型 1 表示 欧几里德距离
  •                                 2 表示 曼哈顿距离(City Block Distance)
    
  •                                 3 表示 象棋格距离(Chessboard Distance)
    
/*      距离变换
 *  QImage &image          输入图像
 *  QImage &otpImage       输出图像
 *  int distant_modle      距离计算模型  1 表示 欧几里德距离
 *                                     2 表示 曼哈顿距离(City Block Distance)
 *                                     3 表示 象棋格距离(Chessboard Distance)
 */
void Distance_Transform(QImage &image,QImage &otpImage,int distant_modle)
{
    int height = image.height();
    int width = image.width();
    int all_size = height * width;
    int x,y;
    int w,h;
    int curr_index;
    float distence;
    float min =10000;
    float max = 0;
    float result;


    int p_4[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
    bool p_condition[4];

    QImage* pImageThreL = new QImage(width,height,QImage::Format_ARGB32);

    QVector<float> mask(all_size);  //前景与背景的模板
    QVector<float> dis_mask(all_size); //距离模板
    //QVector<float> masker(all_size);
    QVector<Point> inside; //内部点的集合
    QVector<Point> outside; //非内部点的集合
    Point temp;


    Init_Image(otpImage,0);

    //二值化处理
    int nDiffGray;
    BYTE  bThreH = DetectThreshold_pro(&image,300,nDiffGray);
    Threshold_pro(&image,*pImageThreL,bThreH);
    Inversion(*pImageThreL);


    //前景模板
    for(y = 1; y < height-1; y++)
    {
        for(x = 1; x < width-1; x++)
        {
             curr_index = y * width + x;
             mask[curr_index] = (qGray(pImageThreL->pixel(x,y)) == 255) ? 1 : -1;
             dis_mask[curr_index] = 0.0;
        }
    }


    //内部点,外部点,孤立点
    for(y=1; y<height-1; y++)
    {
        for(x = 1; x < width-1; x++)
        {
            temp.x = x;
            temp.y = y;

            curr_index = y * width + x;


            if(mask[curr_index]==1)
            {
                for(int k = 0; k<4; k++)
                {
                    p_condition[k] = false;
                    h = y + p_4[k][0];
                    w = x + p_4[k][1];
                    curr_index = h * width + w;
                    if(curr_index>=0 && curr_index<=all_size && mask[curr_index]==1)
                    {
                        p_condition[k] = true;
                    }
                }
                if(p_condition[0] && p_condition[1] && p_condition[2] && p_condition[3])
                    inside.push_back(temp);
            }
            else {
                for(int k = 0; k<4; k++)
                {
                    p_condition[k] = false;
                    h = y + p_4[k][0];
                    w = x + p_4[k][1];
                    curr_index = h * width + w;
                    if(curr_index>=0 && curr_index<=all_size)
                    {
                        if(mask[curr_index]==1)
                            p_condition[k] = true;
                    }
                }
                if(p_condition[0] || p_condition[1] || p_condition[2] || p_condition[3])
                    outside.push_back(temp);
            }
        }
    }

    //cout<<"outside:"<<outside.size()<<endl;
    //cout<<"inside:"<<inside.size()<<endl;
    //距离模式
    switch (distant_modle) {
    //欧式距离
    case 1:
        for(int i = 0; i<inside.size(); i++)
        {
            temp = inside[i];
            x = temp.x;
            y = temp.y;
            curr_index = y * width + x;
            distence = European_Distance(outside,x,y,min,max);
            dis_mask[curr_index] = distence;
        }
        break;
    //城市街区距离
    case 2:
        for(int i = 0; i<inside.size(); i++)
        {
            temp = inside[i];
            x = temp.x;
            y = temp.y;
            curr_index = y * width + x;
            distence = City_blocks_Distance(outside,x,y,min,max);
            dis_mask[curr_index] = distence;
            //cout<<"distence:"<<distence<<endl;
        }
        break;
    //棋盘距离
    case 3:
        for(int i = 0; i<inside.size(); i++)
        {
            temp = inside[i];
            x = temp.x;
            y = temp.y;
            curr_index = y * width + x;
            distence = Chessboard_Distance(outside,x,y,min,max);
            dis_mask[curr_index] = distence;
        }
        break;
    default:
        break;
    }

    result = fabs(min - max);
    for(int i = 1; i<height-1; i++)
    {
        for(int j = 0; j<width-1; j++)
        {
            curr_index = i * width + j;

            if(dis_mask[curr_index] >0)
            {
                int grey = 255*(dis_mask[curr_index] - min) / result;
                otpImage.setPixel(j,i,qRgb(grey,grey,grey));
            }
        }
    }

}

欧式距离计算:

float European_Distance(QVector<Point> &qv,int x,int y,float &dist_min,float &dist_max)
{
    Point tem;
    float min = 10000.0;
    float dist;
    float w,h;

    for(int i = 0; i<qv.size(); i++)
    {
        tem = qv[i];
        w = (x- tem.x)*(x- tem.x);
        h = (y - tem.y)*(y - tem.y);
        dist = sqrtf(w + h);
        if(dist < min)
        {
            min = dist;
        }
    }

    if(min < dist_min)
    {
        dist_min = min;
    }
    if(min > dist_max)
    {
        dist_max = min;
    }
    return min;
}

棋盘距离:

float Chessboard_Distance(QVector<Point> &qvp,int x,int y,float &dist_min,float &dist_max)
{
    Point temp;
    float min = 10000;
    float dist;

    for(int i = 0; i<qvp.size(); i++)
    {
        temp = qvp[i];
        dist = fabs(x-temp.y)+fabs(y-temp.y);
        if(dist < min)
        {
            min = dist;
        }
    }
    if(min < dist_min)
    {
        dist_min = min;
    }
    if(min > dist_max)
    {
        dist_max = min;
    }

    return min;
}

城市街区距离:

float City_blocks_Distance(QVector<Point> qvp,int x,int y,float &dist_min,float &dist_max)
{
    Point temp;
    float min = 10000;
    float dist;
    float w,h;

    for(int i = 0; i<qvp.size(); i++)
    {
        temp = qvp[i];
        w = fabs(x - temp.x);
        h = fabs(y - temp.y);
        dist = fmax(w,h);

        if(dist < min)
        {
            min = dist;
        }
    }

    if(min < dist_min)
    {
        dist_min = min;
    }
    if(min > dist_max)
    {
        dist_max = min;
    }
    return min;
}

效果图:
在这里插入图片描述

在这里插入图片描述

2015-10-19 22:44:11 u012614906 阅读数 5465

写在前面:因学习需要,本人根据章毓晋的《计算机视觉教程》和冈萨雷斯的《数字图像处理》两本书进行学习,中间会穿插相关实践,会有对opencv的学习,以此笔记记录学习过程,激励自己学习的同时,也供大家参考。

声明:转载注明出处,http://blog.csdn.net/accepthjp/article/details/49255375


图像可看做是对辐射强度模式的空间分布的一种表示,是辐射强度模式的一种投影。我们平时看到的图像大多是3-D空间投影得到的2-D成像平面。因此,就有了对此类图像的表示方法,用一个二维数组f(x,y)来表示,x,y表示坐标,f表示在这个坐标位置某种性质的数值。比如:对于灰度图像,f表示灰度值,而对于彩色图像,则需要三个f来分别记录红、绿、蓝三个值。

以上说的是图像的表达,对于图像的显示,则主要依赖于显示设备。根据显示方式不同,图像可以是散点集、区块、数值等多种形式。比如下图中同一张图像的三种显示方式。




接下来是图像的存储。这部分的存储设备和图像文件格式比较熟悉,不多说。特别注意JPEG格式源自JPEG标准,它定义了一个规范的编码数据流,说白了,和哈夫曼编码的意思有点相似,但不完全一样。

然后是像素间的关系。每一个像素的周围8个像素称之为近邻像素,与他们组成4-邻域、对角邻域、8-邻域(有区别)。如果一个像素p在另一个像素q的邻域中,则称两者邻接,如果他们的灰度值还满足某个特定相似准则,则称为连接。如果p与q不连接,但分别与第三个r连接,则称为连通,中间的连接像素(这里是r)构成p与q的通路。

最后是像素间的距离。常使用的距离计算方法有欧氏距离、城区距离、棋盘距离。如下:


具体定义和范数概念参考原书。还有距离变换,将二值图像变为灰度图像的一种特殊变换。

这一篇主要记录了一些图像方面的基本概念,下一篇是对知觉的学习记录。




2013-05-15 21:36:53 jia20003 阅读数 13433

图像处理之距离变换

概述

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

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

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

基本思想

根据度量距离的方法不同,距离变换有几种不同的方法,假设像素点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);
          }
    }
  }

计算快速汉明距离

阅读数 10383

没有更多推荐了,返回首页