车牌字符分割

2024-05-16 06:00:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我面临着从车牌图像中分割字符的问题。 我使用了以下方法提取车牌字符“

  1. 自适应阈值车牌图像。
  2. 选择具有特定纵横比的轮廓。

如附件所示,如果车牌图像有阴影,由于二值化不当,我无法正确分割字符。图像中的阴影合并图像中的相邻字符。

我用不同的窗口大小对图像进行了阈值处理。结果附呈。如果图像中有阴影,如何从图像中分割字符?我正在使用OpenCV。

License plate image with shade

threshoded image 1

thresholded image 2

thresholded image 3

我在OpenCV中使用了以下函数来设置车牌图像的阈值:

cvAdaptiveThreshold(licensePlateImg, threshImg, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, wind);

我试过不同的窗口大小(wind)和不同的adaptiveMethodADAPTIVE_THRESH_MEAN_C and ADAPTIVE_THRESH_GAUSSIAN_C) 获取阈值图像。


Tags: 方法函数图像附件阈值gaussian字符opencv
2条回答

在开始之前,我知道你在OpenCV C++中寻求一个算法的实现,但是我的算法需要FFT和^ {CD1>}包是很棒的。因此,我将使用Python在OpenCV中实现该算法。代码实际上与C++ API非常相似,您可以很容易地将其转录过来。这样,它可以将我学习(或者更确切地说是重新学习)API所需的时间降到最低,我宁愿给你算法和我执行此任务所做的步骤,也不会浪费任何时间。

因此,我将给你一个大致的概述,我将做什么。然后我将向您展示使用numpy, scipy和OpenCV包的Python代码。作为对那些使用MATLAB的人的奖励,我会给你展示MATLAB的等价物,用MATLAB代码来引导!


你能做的就是尝试使用homomorphic filtering。基本上,我们可以用光照和反射率的乘积来表示图像。假设光照是缓慢变化的,是动态范围的主要贡献者。这基本上是低频率的内容。反射率表示物体的细节,并假设变化很快。这也是造成局部对比度的主要因素,本质上是高频内容。

图像可以表示为这两者的乘积。同态滤波尝试并分割这些分量,我们分别对它们进行滤波。完成后,我们将结果合并在一起。由于这是一个乘法模型,因此通常使用log操作,以便我们可以将乘积表示为两个项的和。这两个项分别被过滤、缩放以强调或不强调它们对图像的贡献、求和,然后采取反日志。

明暗处理是由光照引起的,所以我们可以减少明暗处理对图像的贡献。我们还可以提高反射率,这样我们可以得到一些更好的边缘,因为边缘与高频信息相关联。

我们通常用低通滤光片来滤光,而用高通滤光片来滤光。在本例中,我将选择sigma为10的高斯核作为低通滤波器。通过取1并用低通滤波器减去即可得到高通滤波器。我将图像转换成对数域,然后使用低通和高通滤波器在频域中过滤图像。然后缩放低通和高通结果,将这些组件添加回原处,然后获取反日志。该图像现在更适合于阈值化,因为该图像具有较低的变化。

作为额外的后处理,我做的是设置图像的阈值。这些字母比整体背景更暗,因此任何低于某个阈值的像素都将被归类为文本。我选择的门槛是65度。在这之后,我还清除了任何接触边界的像素,然后删除图像中总面积小于160(MATLAB)或120(Python)像素的任何区域。我还裁剪了图像中的一些列,因为它们不需要用于我们的分析。


以下是一些需要注意的事项:

警告1-去除边界

删除任何与边框接触的像素是内置在OpenCV中的而不是。然而,MATLAB有一个等价物,叫做^{}。我将在我的MATLAB代码中使用它,但对于OpenCV,这是以下算法:

  • 找到图像中的所有轮廓
  • 对于图像中的每个轮廓,检查是否有任何轮廓像素在图像的边界内
  • 如果有,请标记此轮廓以便删除
  • 对于我们要删除的每个轮廓,只需用黑色绘制整个轮廓

我在代码中创建了一个名为imclearborder(imgBW, radius)的方法,其中radius是多少像素你想清理边界内的东西。

警告2-删除特定区域下的像素区域

在OpenCV中,删除任何小于一定数量的区域也不会实现。在MATLAB中,这是使用^{}方便地给出的。其基本算法是:

  • 找到图像中的所有轮廓
  • 分析如果要填充内部,每个轮廓的面积填充了多少
  • 任何小于一定量的区域,用黑色填充内部,以清除此轮廓

我创建了一个名为bwareaopen(imgBW)的方法来实现这一点。

注意#3-用于删除像素区域的区域参数

对于Python代码,我不得不使用这个参数,我决定使用120。160用于MATLAB。对于python,120去掉了一些字符,这是不需要的。我猜我的bwareaopen实现与MATLAB的不同,这可能是我得到不同结果的原因。


不用再麻烦了,这里是代码。请注意,我没有使用空间过滤。你可以在OpenCV中使用filter2D,并用高斯核卷积这个图像,但我没有这样做,因为使用低通和高通滤波器时,传统上是在频域进行同态滤波。您可以使用空间过滤来探索这一点,但您还必须在动手之前知道内核的大小。对于频域滤波,你只需要知道滤波器的标准差,这只是一个参数,而不是两个。

另外,对于Python代码,我将您的图像下载到我的计算机上并运行脚本。对于MATLAB,在使用图像处理工具箱读取图像时,可以直接引用该图像的超链接。


Python代码

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()

MATLAB代码

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');

这就是我得到的结果:

Python

请注意,我重新排列了窗口,使它们在一列中对齐。

enter image description here

MATLAB软件

enter image description here

我认为如果你对你提供的第二个二值化图像应用形态学打开操作,你会得到一个好的图像。

相关问题 更多 >