Dee*_*pak 14 python matlab opencv image-processing computer-vision
我在从车牌图像中分割字符时遇到问题.我已经应用以下方法来提取车牌字符"
如果车牌图像中有任何阴影,如附件中所示,由于二值化不当,我无法正确分割字符.图像中的阴影合并图像中的相邻字符.
我用不同的窗口大小对图像进行了阈值处理.结果附后.如果图像中有阴影,如何从图像中分割字符?我正在使用OpenCV.
我在OpenCV中使用了以下功能来限制我的车牌图像:
cvAdaptiveThreshold(licensePlateImg, threshImg, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, wind);
Run Code Online (Sandbox Code Playgroud)
我尝试使用不同的窗口大小(wind
)和不同的adaptiveMethod
(ADAPTIVE_THRESH_MEAN_C and ADAPTIVE_THRESH_GAUSSIAN_C
)来获取阈值图像.
ray*_*ica 38
在开始之前,我知道你正在寻求在OpenCV C++中实现这个算法,但是我的算法需要FFT,并且numpy / scipy
包很棒.因此,我将使用Python为您提供OpenCV中的算法实现.代码实际上与C++ API非常相似,您可以轻松地将其转录.这样,它最大限度地减少了我学习(或者说重新学习......)API所需的时间,我宁愿给你算法和我为完成这项任务所做的步骤,不要浪费任何时间.
因此,我将概述我将要做的事情.然后,我将向您展示使用的Python代码numpy, scipy
和OpenCV包.作为使用MATLAB的人的奖励,我将向您展示MATLAB等效项,并使用MATLAB代码启动!
你可以做的是尝试使用同态过滤.在基本术语中,我们可以根据照明和反射的乘积来表示图像.假设照明缓慢变化并且是动态范围的主要贡献者.这基本上是低频内容.反射率代表物体的细节,并假设快速变化.这也是局部对比度的主要贡献者,并且本质上是高频内容.
图像可以表示为这两者的乘积.同态过滤尝试并拆分这些组件,我们单独过滤它们.然后,我们在完成后将结果组合在一起.由于这是一个乘法模型,因此习惯使用日志操作,以便我们可以将产品表示为两个术语的总和.这两个术语被单独过滤,缩放以强调或不强调它们对图像的贡献,求和,然后采取反日志.
阴影是由于照明,因此我们可以做的是减少此阴影对图像的影响.我们还可以提高反射率,以便我们可以获得更好的边缘,因为边缘与高频信息相关联.
我们通常使用低通滤波器对照明进行滤光,而使用高通滤波器进行反射.在这种情况下,我将选择一个西格玛为10的高斯内核作为低通滤波器.通过1
用低通滤波器进行减法可以得到高通滤波器.我将图像转换为对数域,然后使用低通和高通滤波器在频域中对图像进行滤波.然后我缩放低通和高通结果,将这些组件添加回来,然后进行反日志.此图像现在更适合于阈值处理,因为图像具有低变化.
我作为额外的后期处理所做的是我对图像进行阈值处理.字母比整个背景更暗,因此任何低于特定阈值的像素都将被分类为文本.我选择阈值为强度65.在此之后,我还清除了任何接触边界的像素,然后移除图像中总面积小于160(MATLAB)或120(Python)像素的任何区域.我还裁掉了图像的一些列,因为我们的分析不需要它们.
以下是一些注意事项:
删除任何触摸边框的像素都不会内置到OpenCV中.但是,MATLAB有一个等价的叫做imclearborder
.我将在我的MATLAB代码中使用它,但对于OpenCV,这是以下算法:
我创建了一个imclearborder(imgBW, radius)
在我的代码中调用的方法,其中radius
边框内有多少像素要清除.
在OpenCV中也没有实现删除任何小于一定数量的区域.在MATLAB中,可以方便地使用bwareaopen
.这个的基本算法是:
我创建了一个bwareaopen(imgBW)
为我们做这个的方法.
对于Python代码,我不得不使用这个参数,我决定使用120. 160用于MATLAB.对于python,120摆脱了一些字符,这是不希望的.我猜我bwareaopen
与MATLAB相比的实现是不同的,这可能就是为什么我会得到不同的结果.
不用多说,这是代码.请注意,我没有使用空间过滤.您可以filter2D
在OpenCV中使用并将此图像与高斯内核进行卷积,但是当使用低通和高通滤波器传统上在频域中进行时,我没有这样做,因为同态滤波.您可以使用空间过滤来探索它,但您还必须事先了解内核的大小.使用频域滤波,您只需要知道滤波器的标准偏差,而这只是两个参数的一个参数.
此外,对于Python代码,我将您的图像下载到我的计算机上并运行脚本.对于MATLAB,使用"图像处理"工具箱读取图像时,可以直接引用图像的超链接.
import cv2 # For OpenCV modules (For Image I/O and Contour Finding)
import numpy as np # For general purpose array manipulation
import scipy.fftpack # For FFT2
#### imclearborder definition
def imclearborder(imgBW, radius):
# Given a black and white image, first find all of its contours
imgBWcopy = imgBW.copy()
contours,hierarchy = cv2.findContours(imgBWcopy.copy(), cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
# Get dimensions of image
imgRows = imgBW.shape[0]
imgCols = imgBW.shape[1]
contourList = [] # ID list of contours that touch the border
# For each contour...
for idx in np.arange(len(contours)):
# Get the i'th contour
cnt = contours[idx]
# Look at each point in the contour
for pt in cnt:
rowCnt = pt[0][1]
colCnt = pt[0][0]
# If this is within the radius of the border
# this contour goes bye bye!
check1 = (rowCnt >= 0 and rowCnt < radius) or (rowCnt >= imgRows-1-radius and rowCnt < imgRows)
check2 = (colCnt >= 0 and colCnt < radius) or (colCnt >= imgCols-1-radius and colCnt < imgCols)
if check1 or check2:
contourList.append(idx)
break
for idx in contourList:
cv2.drawContours(imgBWcopy, contours, idx, (0,0,0), -1)
return imgBWcopy
#### bwareaopen definition
def bwareaopen(imgBW, areaPixels):
# Given a black and white image, first find all of its contours
imgBWcopy = imgBW.copy()
contours,hierarchy = cv2.findContours(imgBWcopy.copy(), cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
# For each contour, determine its total occupying area
for idx in np.arange(len(contours)):
area = cv2.contourArea(contours[idx])
if (area >= 0 and area <= areaPixels):
cv2.drawContours(imgBWcopy, contours, idx, (0,0,0), -1)
return imgBWcopy
#### Main program
# Read in image
img = cv2.imread('5DnwY.jpg', 0)
# Number of rows and columns
rows = img.shape[0]
cols = img.shape[1]
# Remove some columns from the beginning and end
img = img[:, 59:cols-20]
# Number of rows and columns
rows = img.shape[0]
cols = img.shape[1]
# Convert image to 0 to 1, then do log(1 + I)
imgLog = np.log1p(np.array(img, dtype="float") / 255)
# Create Gaussian mask of sigma = 10
M = 2*rows + 1
N = 2*cols + 1
sigma = 10
(X,Y) = np.meshgrid(np.linspace(0,N-1,N), np.linspace(0,M-1,M))
centerX = np.ceil(N/2)
centerY = np.ceil(M/2)
gaussianNumerator = (X - centerX)**2 + (Y - centerY)**2
# Low pass and high pass filters
Hlow = np.exp(-gaussianNumerator / (2*sigma*sigma))
Hhigh = 1 - Hlow
# Move origin of filters so that it's at the top left corner to
# match with the input image
HlowShift = scipy.fftpack.ifftshift(Hlow.copy())
HhighShift = scipy.fftpack.ifftshift(Hhigh.copy())
# Filter the image and crop
If = scipy.fftpack.fft2(imgLog.copy(), (M,N))
Ioutlow = scipy.real(scipy.fftpack.ifft2(If.copy() * HlowShift, (M,N)))
Iouthigh = scipy.real(scipy.fftpack.ifft2(If.copy() * HhighShift, (M,N)))
# Set scaling factors and add
gamma1 = 0.3
gamma2 = 1.5
Iout = gamma1*Ioutlow[0:rows,0:cols] + gamma2*Iouthigh[0:rows,0:cols]
# Anti-log then rescale to [0,1]
Ihmf = np.expm1(Iout)
Ihmf = (Ihmf - np.min(Ihmf)) / (np.max(Ihmf) - np.min(Ihmf))
Ihmf2 = np.array(255*Ihmf, dtype="uint8")
# Threshold the image - Anything below intensity 65 gets set to white
Ithresh = Ihmf2 < 65
Ithresh = 255*Ithresh.astype("uint8")
# Clear off the border. Choose a border radius of 5 pixels
Iclear = imclearborder(Ithresh, 5)
# Eliminate regions that have areas below 120 pixels
Iopen = bwareaopen(Iclear, 120)
# Show all images
cv2.imshow('Original Image', img)
cv2.imshow('Homomorphic Filtered Result', Ihmf2)
cv2.imshow('Thresholded Result', Ithresh)
cv2.imshow('Opened Result', Iopen)
cv2.waitKey(0)
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)
clear all;
close all;
% Read in image
I = imread('http://i.stack.imgur.com/5DnwY.jpg');
% Remove some columns from the beginning and end
I = I(:,60:end-20);
% Cast to double and do log. We add with 1 to avoid log(0) error.
I = im2double(I);
I = log(1 + I);
% Create Gaussian mask in frequency domain
% We must specify our mask to be twice the size of the image to avoid
% aliasing.
M = 2*size(I,1) + 1;
N = 2*size(I,2) + 1;
sigma = 10;
[X, Y] = meshgrid(1:N,1:M);
centerX = ceil(N/2);
centerY = ceil(M/2);
gaussianNumerator = (X - centerX).^2 + (Y - centerY).^2;
% Low pass and high pass filters
Hlow = exp(-gaussianNumerator./(2*sigma.^2));
Hhigh = 1 - Hlow;
% Move origin of filters so that it's at the top left corner to match with
% input image
Hlow = ifftshift(Hlow);
Hhigh = ifftshift(Hhigh);
% Filter the image, and crop
If = fft2(I, M, N);
Ioutlow = real(ifft2(Hlow .* If));
Iouthigh = real(ifft2(Hhigh .* If));
% Set scaling factors then add
gamma1 = 0.3;
gamma2 = 1.5;
Iout = gamma1*Ioutlow(1:size(I,1),1:size(I,2)) + ...
gamma2*Iouthigh(1:size(I,1),1:size(I,2));
% Anti-log then rescale to [0,1]
Ihmf = exp(Iout) - 1;
Ihmf = (Ihmf - min(Ihmf(:))) / (max(Ihmf(:)) - min(Ihmf(:)));
% Threshold the image - Anything below intensity 65 gets set to white
Ithresh = Ihmf < 65/255;
% Remove border pixels
Iclear = imclearborder(Ithresh, 8);
% Eliminate regions that have areas below 160 pixels
Iopen = bwareaopen(Iclear, 160);
% Show all of the results
figure;
subplot(4,1,1);
imshow(I);
title('Original Image');
subplot(4,1,2);
imshow(Ihmf);
title('Homomorphic Filtered Result');
subplot(4,1,3);
imshow(Ithresh);
title('Thresholded Result');
subplot(4,1,4);
imshow(Iopen);
title('Opened Result');
Run Code Online (Sandbox Code Playgroud)
这是我得到的结果:
请注意,我重新安排了窗口,使它们在一列中对齐.