2016-09-09 00:53:31 lpsl1882 阅读数 2528

  图像处理分析过程中,检测特定的形状是重要的一步。霍夫变换(Hough)通过转换坐标系,将特定形状的检测映射到参数空间中,从而根据参数空间中的值来确定特定形状的相关信息。
  Hough变换的比较简单的应用例子有检测直线和检测圆。

检测直线

  设空间中有若干点,我们要判断这些点是否能构成一条直线,即为直线检测。平面中直线的通用公式为xcos(θ)+ysin(θ)=ρ。常用的y=wx+b公式,因为不能兼容y=b的情况,所以不能使用。对于某个点,其坐标是(xi,yi),过该点的直线有无数条,这些直线统一表示为xicos(θ)+yisin(θ)=ρ,其中xi,yi是常量。反过来看,代表这些直线的公式,可以看做θ为自变量,ρ为因变量,xi,yi为常量参数的直线公式。这样,在x-y空间过(xi,yi)的无数条直线,可以在θρ空间中用一条线代表。见下图:
  这里写图片描述
  这里写图片描述
  上图是x-y空间,下图是θρ空间。其中红、绿、蓝三条线可以汇聚成一个点,说明这三条线对应的点,其在θρ空间中的直线参数是一样的。反过来就是说,穿过这三个点的无数直线中,有“三”条直线,其θ,ρ值相同,这“三“条直线是一根直线,即这三个点可以共线。
  

检测圆

  设空间有若干点,我们要判断这些点是否能构成一个圆的轮廓,即为圆检测。圆的表达式为(xx)2+(yy)2=R,参数有x,y,R。这说明,圆对应的映射空间是三维的,即xyR空间。x,y都表示空间,因此我们可以暂时将R设为常量,构建xy空间,令x’为自变量,y’为因变量,作图如下:
  这里写图片描述
  这里写图片描述
  上图是x-y空间,下图是x’-y’空间。图中绘制了一个圆和一个矩形,其中圆的轮廓并不是完全规则的。经过Hough变换后,圆上的点的变换曲线基本汇聚在一起,而矩形上的点则不能汇聚,这样就检测到圆。由于我们获取的图像并不一定是规则图形,其在参数空间中不一定能汇聚到一个点,而是在一个区域中汇聚起来,为了容许这类误差,我们可以用窗来检测参数空间中的曲线汇聚区域,而不是找曲线汇聚点,以此来检测不完全规则的特定形状。
  如果我们不知道R的值,那么我们就需要给定R取值的离散区间[R1,R2...Rn],取该区间中的值,重复做n次Hough变换检测。这样的话工作量会非常大,为了提升效率,往往会借助图像中的其他特征。
  另外,我们可以看出,由于不知道圆的尺度,我们不得不重复做多次检测。在实际的形状检测工作中,我们并不知道需要检测的复杂形状,经过了何种平移、缩放、旋转甚至是扭曲,因此需要引入不变性特征,或者针对所有可能的平移、缩放、旋转变换情况,统统做一遍检测。物体检测跟踪需要相当多的计算量。据了解,人脑为了进行视觉模式识别,至少消耗了一半的神经资源,所以人可以闭目养神,却不能捂耳朵、捏住鼻子养神:)

2018-03-18 14:31:25 qq_27591163 阅读数 510

图像的灰度变换是图像的一种点处理算法,指图像任意点的增强仅仅依赖于该点的灰度值。而在下一节将会使用的是图像的模板变换。

1.图像的反转变换

灰度级为[0,L-1]则:反转变换为:g(x,y)=L-1-f(x,y)

其中g(x,y)位输出图像,f(x,y)为输入图像。

2.图像的对数变换

此种变换使一窄带低灰度输入图像转换映射为一宽带输出图像:

y = a + log(1+x)/b

其中a控制曲线的垂直偏移量,b控制曲线的弯曲程度,b越大则曲线越弯曲。

3.图像的幂次变换:

y = cx**r + b

其中c,r均为正数,使x与y的取值均在0-255则;

y = 255c(x/255)**r+b

幂次变换的性质为:

当r<0时,变换函数曲线在正比线上方,此时与对数函数类似,使图像变亮

当r>0时,变换函数曲线在正比线下方,此时扩展高灰度级,压缩低灰度级,使图像变暗。

4.灰度均衡化

灰度均衡化的公式推导涉及到了微积分的知识,均衡化的作用是使一副图像其像素占有全部可能的灰度级并且分布均匀,则这样的图像有高对比度和多变的灰度色调。

{
	float newMi[256];
	LPBYTE p_data = getData();
	int width = getWidth();
	int height = getHeight();
	LPBYTE temp = new BYTE[width*height];
	memcpy(temp, p_data, width*height);
	int bMap[256];
	newMi[0] = midu[0];
	for (int i = 1; i < 256; i++) {
		newMi[i] = newMi[i - 1] + midu[i];
	}
	for (int i = 0; i < 256; i++)
	{
		bMap[i] = (int) (newMi[i] * 255.0 + 0.5f);//这里后边的式子一定要括起来因为强制类型转换的优先级要高
	}
	for(int j=0;j<height;j++)
		for(int i=0;i<width;i++)
		{
			BYTE T = temp[width*j+i];
			temp[width*j+i] = bMap[T];
		}
	memcpy(p_data, temp, width*height);
}

2015-08-26 10:37:33 u013162930 阅读数 10814

最近在学习冈萨雷斯的《数字图像处理》,想把整理的笔记和自己实现的小实验整理在博客上~


今天的主题是图像的灰度变换:

g(x,y)= T [ f(x,y)]

f(x,y)是输入图像,g(x,y)是处理后的图像,T是在点(x,y)邻域上定义的关于f 的一种算子。

T处理,从输入图像的左上角开始,以水平扫描的方式逐像素地处理。当该邻域的圆点位于图像的边界上时,部分邻域将位于图像的外部。此时,不是忽略外侧邻点,就是用0或者其他指定的灰度值填充图像的边缘。被填充的边界的厚度取决于邻域的大小。

以上的描述过程称为空间滤波,其中,邻域与预定义的操作一起称为空间滤波器(也称为空间掩模、核、模板或窗口)。


最小邻域的大小为1×1。在这种情况下,g 仅取决于点(x,y)处的灰度值f ,而T则成为一个形如下式的灰度(也称为灰度级或映射)变换函数:

S = T(r)

其中,为表达方便,另r和S分别表示变量,即g和f 在任意点(x,y)处的灰度。


例如,如果T(r)有如图所示的形式


对f 中每一个像素施以变换产生相应的g的像素的效果将比原图像有更高的对比度。这种技术被称为对比度拉伸。

极限情况下,会产生二级(二值)图


图像增强技术是面向问题的,没有通用的“理论”。


一些基本的灰度变换函数:

①图像反转

S = L - 1 - r

通俗的说,就是图像的黑边反转交换。

特别适用于增强嵌入在一幅图像的暗区域中的白色或灰色细节。

②对数变换

S = c*log(1+ r)


改变换将输入中范围较窄的低灰度值映射为输出中较宽范围的灰度值,对范围较宽的高输入灰度值映射为输出中较窄范围的灰度值。

我们一般使用这种类型的变换来扩展图像中的暗像素值,同时压缩更高灰度级的值。

反对数变换的作用与此正好相反。

对数函数的一般形状的任何曲线,都能完成图像的灰度级的扩展和压缩,但是一会介绍的幂律变换对于这个目的更为通用。

对数函数有个重要的特征,即它压缩像素值变换较大的图像的动态范围。这一特征一般被应用于傅里叶频谱中。

通常,频谱值的范围从0到10^6,甚至更高。尽管计算机能毫无疑问的处理这一范围的数字,但图像的显示系统通常不能如实地再现如此大范围的灰度值。因而,最终结果是许多重要的灰度细节在典型的傅里叶频谱的显示中丢失了。

如果我们先将这些频谱进行对数函数的对比度拉伸,再线性的缩放到新的值域,并在同一个8比特显示系统中显示频谱的结果。会看到很多丰富的细节。

③幂律(伽马)变换

S = c* r ^γ


习惯上,幂律方程中的指数被称为伽马

用于校正幂律响应现象的处理称为伽马校正

幂律变换与对数变换一样,也可以扩展和压缩一些灰度级,且应用的更为广泛。

④分段线性变换函数

优点:形式可以是任意复杂的。

缺点:技术说明要求用户输入。


上面就是关于灰度变换的一些总结。

下面我想做一个小实验,对一幅光照不均匀的图像,进行一下伽马变换的对比度拉伸,调整一下显示的亮度。

我是用VB.NET的Emgu来实现的。

这个是原图


'伽马变换的灰度拉伸
'处理光照不均匀的图像
Dim img As New Image(Of Gray, Byte)("C:\test.bmp")
Dim height As Integer = img.Height
Dim width As Integer = img.Width
Dim gama As Double = 0.4

Dim Sbigest As Integer = 0
Dim Sfewest As Integer = 255
For i = 0 To height - 1
    For j = 0 To width - 1
        If img.Data(i, j, 0) < Sfewest Then
            Sfewest = img.Data(i, j, 0)
        End If
        If img.Data(i, j, 0) > Sbigest Then
            Sbigest = img.Data(i, j, 0)
        End If
    Next
Next
For i = 0 To height - 1
    For j = 0 To width - 1
        img.Data(i, j, 0) = (img.Data(i, j, 0) ^ gama - Sfewest ^ gama) / (Sbigest ^ gama - Sfewest ^ gama) * 255
    Next
Next
img.Save("C:\test-result.bmp")

处理后的结果,其实效果还可以。只是不道为啥图片一粘贴到博客上,较深的背景就会变成绿色的了。


2015.9.3补充~

最近细致的学习了灰度变换以及直方图的一些相关的处理,回过头来,想把这篇博文中的那张图处理下。

之前的实验结果,伽马变换后的图片,四个角的部位都有阴影。这是因为那些部分的灰度值都较小,图像较暗,伽马变换后也难以校正。

如果想校正这部分区域,就需要考虑对比度的问题,才能对我们想要的部分进行有效的增强。

因此我想求出整体的方差与局部的方差。如果局部的方差大于整体方差,则认为是文字与背景的交界区域。否则,则认为是背景。

以下是代码实现。放假在家没有VS,只好用matlab实现的~

clear all;
close all;
clc;

I = imread('C:\test\src.bmp');  
I = rgb2gray(I);
[height,width] = size(I);
E1 = 1.6;
E2 = 10;
k0 = 0.9;
k1 = 0.8;
k2 = 0.2;

m = 0;
for i=1:height
    for j=1:width
        m = m + double(I(i,j));
    end
end
%灰度级平均值
m = m / (height * width);
variance = 0;
for i=1:height
    for j=1:width
        variance = variance + (double(I(i,j) - m))^2;
    end
end
%灰度方差
variance = variance / (height * width);

I2 = I;
for i=1:height
    for j=1:width
        
        m1 = 0;        
        for h1 = i - 3: i + 3
            for h2 = j - 3: j + 3
                if(h1)<1 || (h2)<1 || (h1)>height || (h2)>width
                    m1 = m1 + m;
                else
                    m1 = m1 + double(I(h1,h2));
                end 
            end
        end
        m1 = m1 / 49;
        variance1 = 0;
        for h1 = i - 3: i + 3
            for h2 = j - 3: j + 3
                if(h1)<1 || (h2)<1 || (h1)>height || (h2)>width
                    variance1 = variance1 + (m1 - m)^2;
                else
                    variance1 = variance1 + (double(I(h1,h2)) - m1)^2;
                end 
            end
        end
        variance1 = variance1 / 49;

        if  (variance1 >= k1 * variance) && (m1 <= I(i,j))
           %方差大于平均方差
           %该点处的灰度值大于邻域的平均灰度值
           I2(i,j) = E1*I(i,j) ;
        elseif (variance1 >= k1 * variance) && (m1 > I(i,j))
           
        elseif (variance1 < k2 * variance)           
           I2(i,j) = 2*E2*I(i,j) ;
        else
        end        
    end
end
imwrite(I2,'C:/test/test_result.bmp','bmp');



图片边上的黑边是因为邻域的选取造成的。





2016-06-05 11:02:22 sinat_34035510 阅读数 6807

霍夫(HOUGH)变换

        霍夫变换是图像处理中用来从图像中分离出具有某种相同特征的几何形状(通常,直线,圆等)的常用方法。经典的霍夫变换常用来检测直线,圆,椭圆等。

为什么要进行霍夫变换,当然是为了实现某种目的,比如检测,(废话)。它是利用图像全局特性而将边缘像素连接起来组成区域封闭边界的一种方法。在预先知道区域形状的条件下,利用霍夫变换可以方便地得到边界曲线而将不连续的边缘像素点连接起来。

霍夫变换的主要优点是受噪声和曲线间断的影响小。利用霍夫变换还可以直接检测某些已知形状的目标

霍夫变换的基本思想是点 —— 线的对偶性(duality),当然这只不过是所有人都这样说了,所谓线的对偶性就是线与线的某种变换之后的对应或者映射关系,实际上霍夫变换是直角坐标系空间线与变换域空间的线的映射关系,考虑傅里叶变换?当然就是说变换的目的就是便于分析。具体原理如下:

     在图像空间XY里,所有过点(x,y)的直线都满足方程:

                         y = px + q    

它也可写成:q = -px + y可以认为是参数空间PQ中过点(p’, q’)的一条直线。在图像空间中共线的点对应在参数空间里相交的线。



在图像空间中共线的点对应在参数空间里相交的线.反过来,在参数空间中相交于同一个点的所有直线在图像空间里都有共线的点与之对应。这就是点——线的对偶性。当然一般选取变换空间是时用的是极坐标空间(为什么?因为图像空间中垂直的直线p趋近于无穷!),霍夫变换根据这些关系把在图像空间中的检测问题转换到参数空间里,通过在参数空间里进行简单的累加统计完成检测任务在具体计算时,需要在参数空间PQ里建一个2-D的累加数组。设这个累加数组为A(p, q),如图所示,其中[pmin, pmax]和[qmin, qmax] 分别为预期的斜率和截距的取值范围。开始时置数组A为零,然后对每一个图像空间中的给定点,让p取遍P轴上所有可能的值,并根据式q = -px + y算出对应的q。再根据p和q的值(设都已经取整)对A累加:A(p, q)=A(p, q)+1。  累加结束后,根据A(p,q)的值就可知道有多少点是共线的,即A(p, q) 的值就是在(p, q) 处共线点的个数。同时(p, q) 值也给出了直线方程的参数,使我们得到了点所在的线。


具体实现步骤:

1)、构造一个P、Q空间的二维累加数组A(p,q)

2)、从f(x,y)的指定区域中取(xi,yi),按方程q=-pxi+yi在[pmin,pmax]中遍取可能的p值计算得到可能的q值。

3)、在对应的位置计算A(p,q) =A(p,q)+1

4)、重复2)、3)直到将从f(x,y)的指定区域中的所有点取完。此时,A(p,q)数组中最大值所对应的p,q就是方程y=px+q中的p、q值。

5)、根据y=px+q绘出f(x,y)中的直线

区域的选择:来自确认存在直线的区域。

坐标的选择:来自对存在的直线参数的估测。

霍夫变换不仅可用来检测直线和连接处在同一条直线上的点,也可以用来检测满足解析式f(x, c)=0形式的各类曲线,并把曲线上的点连接起来,这里x是一个坐标矢量,在2-D图像中是一个2-D矢量,c是一个系数矢量,它可以根据曲线的不同从2-D到3-D,4-D,…。换句话说,对写得出方程的图形都可利用霍夫变换检测

        例如圆周的检测。圆的一般方程是:

               (x - a)^2 + (y - b) ^2 = r^2

       式中有3个参数a,b, r,所以需要在参数空间里建立一个3-D的累加数组A,其元素可写为A(a, b, r) 。我们可让a和b依次变化而根据上式算出r,并对A累加:A(a, b, r) = A(a, b, r) + 1。所以其原理与检测直线上的点相同,只是复杂性增加了。

       从理论上来说,计算量和累加器尺寸随参数个数的增加是指数增加的,所以实际中霍夫变换最适合于检测较简单(即其解析表达式只含有较少参数)曲线上的点。

       设圆的半径r为已知,问题转化到2-D参数空间,如下图。原来参数的轨迹为整个圆锥部分表面,如果r已知,则参数的轨迹是半径为r的圆周。这里图像空间中的边界和参数空间里的轨迹都是圆周,所以这里是圆周——圆周对偶性。


至于代码,在MATLAB工具箱中本身集成了hough变换的函数,SO。。。。就不贴了

2018-12-05 20:10:03 yql_617540298 阅读数 82

一、霍夫变换思想(Hough Transform)

        霍夫变换主要是利用图片所在的空间和霍夫空间之间的变换,将图片所在的直角坐标系中具有形状的曲线或直线映射到霍夫空间的一个点上形成峰值,从而将检测任意形状的问题转化成了计算峰值的问题;

        即在图片所在的直角坐标系的一个直线,转换到霍夫空间便成了一点,并且是由多条直线相交而成,我们统计的峰值也就是该相交点的橡胶线的条数。

        Hough变换的基本原理在于利用点与线的对偶性,将原始图像空间的给定曲线通过曲线表达形式变为参数空间的一个点。这样就把原始图像给定曲线的检测问题,转化为检测参数空间的峰值问题,也就是把检测整体特性转化为检测局部特性。比如直线,椭圆,圆,弧线等。

(1)设已知一黑白图像上画了一条直线,要求出这条直线所在的位置。我们知道,直线的方程可以用y=k*x+b 来表示,其中k和b是参数,分别是斜率和截距。也就是说,我们将原始图像需要检测的直线,表示成y = k*x + b, 只要找出唯一的k,b即可检测出该直线。该直线在原始图中是一系列离散点的集合,过该直线上某一点(x0,y0)的所有直线的参数都会满足方程y0=kx0+b。即点(x0,y0)确定了一条直线。而方程y0=kx0+b在参数k--b平面上是一条直线,(也可以是方程b=-x0*k+y0对应的直线).即点(x0,y0)在参数空间确定了一条直线。

(2)这样,图像x--y平面上的一个前景像素点就对应到参数平面上的一条直线。因此,图像x-y内需检测直线上的N个点,在参数平面会有N条直线。而图像x-y内的直线有唯一一个k,b,因此,相应的参数平面N条直线必然有唯一一个交点。

(3)图示:

二、倾斜文本校正

import os
import cv2
import math
import numpy as np
from scipy import misc, ndimage
from PIL import Image

filepath = 'C:/Users/Administrator/Desktop/test'
count = os.listdir(filepath)
resultpath = 'C:/Users/Administrator/Desktop/results'
 
#for filename in os.listdir(filepath):
for j in range(1,len(count)+1):
    img = cv2.imread(filepath+'/rgb_'+str(j).zfill(4)+'.png')
    img1 = Image.open(filepath+'/rgb_'+str(j).zfill(4)+'.png')
    img1 = img1.convert('RGBA')
    #img = cv2.imread(filepath+'/'+str(j).zfill(4)+'.png')
    #print("img",img)
    #img1 = Image.open(filepath+'/'+str(j).zfill(4)+'.png')
    n = img.shape[0]
    m = img.shape[1]
    #print(m,n)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray,50,150,apertureSize = 3)
    
    #霍夫变换
    lines = cv2.HoughLines(edges,1,np.pi/180,0)
    for rho,theta in lines[0]:
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a*rho
        y0 = b*rho
        x1 = int(x0 + 1000*(-b))
        y1 = int(y0 + 1000*(a))
        x2 = int(x0 - 1000*(-b))
        y2 = int(y0 - 1000*(a))
    if x1 == x2 or y1 == y2:
        continue
    t = float(y2-y1)/(x2-x1)
    rotate_angle = math.degrees(math.atan(t))
    if rotate_angle > 45:
        rotate_angle = -90 + rotate_angle
    elif rotate_angle < -45:
        rotate_angle = 90 + rotate_angle
    rotate_img = ndimage.rotate(img, rotate_angle)
    misc.imsave(resultpath+'/'+'rgb_'+str(j).zfill(4)+'.png', rotate_img)

可以看到得到的结果会出现黑色色块:

region = img1.crop((5,5,10,10))
region = np.array(region)
R = np.mean(region[:,:,0])
G = np.mean(region[:,:,1])
B = np.mean(region[:,:,2])
    
card = Image.new("RGBA", (m, n), (int(R),int(G),int(B)))
card.paste(rotate_image, (0, 0, m, n), rotate_image)

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