pdf417条码的符号结构

预处理步骤

OSTU二值化

假定该图像根据双模直方图包含两类像素:前景像素和背景像素。计算能将两类分开的最佳阈值,要使得它们的类内方差最小;由于两两平方距离恒定,即它们的类间方差最大。

类间方差:前景像素占比w0,期望为u0,背景像素占比w1,期望为u1,整个图像期望为u=w0*u0+w1*u1,分割像素点为t,类间方差为g(t) = w0*(u0-u)^2+w1*(u1-u)^2,当类间方差最大时,t即为最佳阈值。

由于w1=1-w0,可得到g(t)=w0 (t)*(u - u0 (t))^2/(1 - w0 (t))

function imageBW = Ostu(gray)
%统计各灰度级像素在整幅图像中的个数
Hist = imhist(gray);
%计算每个灰度级在图像中所占的比例
[Row,Col]=size(gray);
dHist=Hist /(Row*Col);
%去除两边不存在的灰度级
L=256;
st = 0; nd = 0;
for i=1:L if dHist(i) ~= 0 st = i;break;end
end
for i=L:-1:1if dHist(i) ~= 0 nd = i;break;end
end
dHist = dHist(st:nd);
L = size(dHist,1);
% 计算前t个像素的累加概率w0 (t)和像素期望值u0 (t)
w0 = zeros(L,1);  u0 = zeros(L,1);
for t = 1 : Lw0(t) = sum(dHist(1:t));u0(t) = sum((st-1:st+t-2)*dHist(1:t)) / w0(t);
end
u = u0(L);  %总期望
% 方差
variance = zeros(L,1);
for t = 1 : Lvariance(t) = w0(t)*(u-u0(t))^2/(1-w0(t));
end
% 找出最大方差时的t
t = 1;
for i = 1 : Lif variance(t) < variance(i)t = i;end
end
%二值化
PXD = t-2+st; %阈值像素
for i = 1:Rowfor j = 1:Colif gray(i,j) > PXDgray(i,j) = 0;elsegray(i,j) = 255;endend
end
%显示二值化图像
imageBW = gray;
%figure;
%imshow(imageBW); title('Ostu二值化');
end

膨胀腐蚀

  • 膨胀:结构元素B在图像A上的前景像素上平移后的集合
function  transImage=mdilate(Image,B)
[H,W]=size(Image);
[BH,BW]=size(B);
%边界扩展
H2 = H+BH-1; W2 = W+BW-1;
Image2=zeros(H2,W2);
Image2(round(BH/2):round(BH/2)+H-1,round(BW/2):round(BW/2)+W-1)=Image;
transImage = zeros(H2,W2);
for m=1:Hfor n=1:Wif Image2(m+round(BH/2)-1,n+round(BW/2)-1)~=0   %取原点为中心transImage(m:m+BH-1,n:n+BW-1) = (Image2(m:m+BH-1,n:n+BW-1) | B(1:BH,1:BW))*255;endend
end
%去除扩展
transImage = transImage(round(BH/2):round(BH/2)+H-1,round(BW/2):round(BW/2)+W-1);
end
  • 腐蚀:结构元素B与图像A上前景像素完全匹配的原点位置的集合
function  transImage=merode(Image,B)
[H,W]=size(Image);
[BH,BW]=size(B);
H2 = H+BH-1; W2 = W+BW-1;
Image2=zeros(H2,W2);
Image2(round(BH/2):round(BH/2)+H-1,round(BW/2):round(BW/2)+W-1)=Image;
transImage = zeros(H2,W2);
for m=1:Hfor n=1:Wif Image2(m+round(BH/2)-1,n+round(BW/2)-1)~=0tmp=Image2(m:m+BH-1,n:n+BW-1);  %窗口内所有点if sum(sum(tmp&B)) == sum(sum(B&1))  %完全匹配transImage(m+round(BH/2)-1,n+round(BW/2)-1) = 255;  %中心为255endendend
end
transImage = transImage(round(BH/2):round(BH/2)+H-1,round(BW/2):round(BW/2)+W-1);
end

形态学变换去除多余连通域

  • 利用重构取出与边界相连的连通域

    形态学重构:是一种涉及到两幅图像和一个结构元素的形态学变换。一副图像,即标记(marker),是变换的开始点,用来约束变换经过的过程。结构元素用于定义连接性。

    去除边界连通域:标记(marker)为原图像的边界值,是变换Hk的开始点,每次变换都膨胀后与掩膜(原图像)取交集,直到H不在改变,此时H即为与边界相连的连通域

  • 进行开运算和闭运算,去除细小的连通域,再把二维码揉成团

    标记各个连通域,面积小于阈值(最大连通域面积的一半)的去除。

function  I = connectdomin(im)
[row,col] = size(im);
%figure;imshow(im);
%去除边界连通域
marker = im;
marker(2:row-1,2:col-1) = 0;
g = im;
h1 = zeros(row,col);
h2 = marker;
se = ones(3,3);
%figure;
while sum(sum(h2 == h1)) ~= row*colh1 = h2;h2 = (mdilate(h1, se)&g)*255; %imshow(h2),title('边界连通域');
end
%class(im)
%class(h2)
im = im - uint8(h2);
figure;imshow(im),title('去除边界连通域');%开运算
se = ones(3,3);
I = merode(im, se);
%figure;imshow(I);
I = mdilate(I, se);
%figure;imshow(I);title('开运算');
%闭运算
se=ones(20,20);
I = mdilate(I, se);
%figure;imshow(I);
I = merode(I, se);
%figure;imshow(I);title('闭运算');
%去除多余连通域
[L,num] = bwlabel(I);
count = zeros(1,num);
%统计各个连通域面积
for i = 1:num[r,c] = find(L==i);count(i) = size(r,1);
end
%阈值
T = round(max(count)/2);
%去除
for i = 1:numif count(i) < T[r,c] = find(L==i);I(r,c) = 0;end
end
figure;imshow(I),title('去除多余连通域');
end

Hough变换(直角坐标系)

功能: 查找二维码边缘直线
思路:

  • 按照笛卡尔坐标下的参数化,一副图像中通过坐标(x,y)的共线像素点,是通过斜率为m截距为c的像素连接的,即满足:

    c=-m*x+y

  • 根据这条公式,建立一个累加器矩阵H[c][m]。然后以一定的精度统计经过前景像素点的每一条直线的参数c,m然后H[c][m]+1,直到到遍历所有的前景像素。

  • 注意若以图像左上角顶点为原点,对图像坐标(row,col)而言row为竖直的y,col为水平的x,且正方向为向右和向下,故可建立向右向下的坐标系,则直线方程为c = y + m*x ,其中m = (y2-y1)/(x1-x2),便于理解。

  • 为方便记录c,分为两个累加数组,Hr记录-45到45度,Hc记录45-135度,可以算出c的范围分别为-col到row+col、-row到row+col。

  • 注意矩阵下标为正

代码:

function [x,y]=Hough(im)
[row,col] = size(im);
%找到经过每两个前景像素的直线,记录斜率m对应的角度n和截距c
%累加矩阵 -45—45和45-90、90-135(-45—0)
Hr = zeros(2*col+row+1, 90);
Hc = zeros(2*row+col+1, 90);
%记录前景像素位置
lines = zeros(row*col,2);
k = 0;
for i = 1:rowfor j = 1:colif im(i,j) ~= 0k = k+1;lines(k,1) = i; lines(k,2) = j;endend
end
% 坐标系为向下 向右
% c = y + m*x   m = (y2-y1)/(x1-x2)
for i = 1:kfor j = i+1:kif lines(i,2) ~= lines(j,2)m = (lines(i,1)-lines(j,1)) / (lines(j,2)-lines(i,2));   n = round(atan(m)*180/pi);  % 范围为-90~90if n > -90 && n < -45n = n + 180;    % 不在所需范围内需要转换到90~134endif n >= -45 && n <= 44c = lines(i,1) + lines(i,2)*m;% 保证下标为正sc = int16(c) + col + 1;sn = int16(n) + 45 + 1;Hr(sc, sn) = Hr(sc, sn) + 1;elseif n >= 45 && n <= 134c = lines(i,2) + lines(i,1)/m;sc = int16(c) + row + 1;sn = int16(n) - 45 + 1;Hc(sc, sn) = Hc(sc, sn) + 1;endendendend
end
figure;
surf(Hr,'EdgeColor','None');title('Hr的surf');
figure;
surf(Hc,'EdgeColor','None');title('Hc的surf');
%寻找四个峰值即为四条边所在直线
Hr2 = zeros(2*col+row+1+16, 90+16);
Hr2(9:2*col+row+1+8,9:90+8) = Hr;
[c1, n1] = find(Hr2==max(max(Hr2)));
Hr2(c1-8:c1+8, n1-8:n1+8) = 0;
[c2, n2] = find(Hr2==max(max(Hr2)));
Hc2 = zeros(2*row+col+1+16, 90+16);
Hc2(9:2*row+col+1+8,9:90+8) = Hc;
[c3, n3] = find(Hc2==max(max(Hc2)));
Hc2(c3-8:c3+8, n3-8:n3+8) = 0;
[c4, n4] = find(Hc2==max(max(Hc2)));
%还原斜率k和截距b
m1 = (n1-8-45-1)*pi/180;
k1 = tan(m1);
b1 = c1-8-col-1;
m2 = (n2-8-45-1)*pi/180;
k2 = tan(m2);
b2 = c2-8-col-1;
m3 = (n3-8+45-1)*pi/180;
if m3 > 90 && m3 <= 134m3 = m3 - 180;    %90~135
end
k3 = tan(m3);
b3 = k3*(c3-8-row-1);
m4 = (n4-8+45-1)*pi/180;
if m4 > 90 && m4 <= 134m4 = m4 - 180;    %90~135
end
k4 = tan(m4);
b4 = k4*(c4-8-row-1);
%求四个交点
x = [(b3-b1)/(k3-k1) (b3-b2)/(k3-k2) (b4-b1)/(k4-k1) (b4-b2)/(k4-k2)];
y = [b1-k1*x(1) b2-k2*x(2) b1-k1*x(3) b2-k2*x(4)];

双线性变换

功能: 矫正二维码

双线性变换可以用以下矩阵表示:


关键在于确定原图像点与目标图像点的对应关系

提供一个思路:使用相对坐标,取相对于P1的距离L,进行排序,那么L12必然就是短边,由于图像拍摄角度,对角线可能会比长边短,故L13不一定是长边。之后只需判断P1、P2哪个对应左上角坐标(0,0),P1、P2确定后,P3、P4可以通过P12和P34的方向是否一致,判断那个对应右上角坐标,同时确定L13和L14哪个为长边。

为方便计算,将原图像看作是输出图像变换而成的,使用四个顶点及对应点求出变换矩阵

function newimg = bilinear_transform(img, x, y)
%figure; imshow(img);title('原图');
[row,col] = size(img);
%对原图的四个顶点P1、P2、P3、P4按到P1的距离排序
%原图点
point = zeros(4,3);
point(:,2) = x; %横
point(:,1) = y; %纵
point(:,3) = sqrt((point(1,1)-point(:,1)).^2 + (point(1,2)-point(:,2)).^2); %各点到P1的距离
%按到点1距离排序
point = round(sortrows(point,3));
%对应目标图点
%当P1、P2在P3、P4上方时,若p1在p2右边,则P1对应左上角顶点,否则P2对应左上角顶点
%当P12与P34方向一致,说明P3对应右上角顶点,L13为长边,否则P4对应右上角顶点,L14对应长边
%而当P1、P2在P3、P4下方时,若p1在p2右边,则P2对应左上角顶点,否则P1对应左上角顶点。
if max(point(1,1),point(2,1)) < max(point(3,1),point(4,1))  %p12在上方if point(1,2)-point(2,2) > 0  %p1在p2右边if (point(1,1)-point(2,1))/(point(3,1)-point(4,1)) > 0  %p12与p34方向一致dst = [0 0;point(2,3) 0;0 point(3,3);point(2,3) point(3,3)];newcol = point(3,3);elsedst = [0 0;point(2,3) 0;point(2,3) point(4,3);0 point(4,3)];newcol = point(4,3);endelseif (point(1,1)-point(2,1))/(point(3,1)-point(4,1)) > 0  %p12与p34方向一致dst = [point(2,3) 0;0 0;point(2,3) point(3,3);0 point(3,3)];newcol = point(3,3);elsedst = [point(2,3) 0;0 0;0 point(4,3);point(2,3) point(4,3)];newcol = point(4,3);endend
else  %p1在下方if point(1,2)-point(2,2) < 0  %p1在p2左边if (point(1,1)-point(2,1))/(point(3,1)-point(4,1)) > 0  %p12与p34方向一致dst = [0 0;point(2,3) 0;0 point(3,3);point(2,3) point(3,3)];newcol = point(3,3);elsedst = [0 0;point(2,3) 0;point(2,3) point(4,3);0 point(4,3)];newcol = point(4,3);endelseif (point(1,1)-point(2,1))/(point(3,1)-point(4,1)) > 0  %p12与p34方向一致dst = [point(2,3) 0;0 0;point(2,3) point(3,3);0 point(3,3)];newcol = point(3,3);elsedst = [point(2,3) 0;0 0;0 point(4,3);point(2,3) point(4,3)];newcol = point(4,3);endend
end
%求变换矩阵
a = [dst(1,1) dst(2,1) dst(3,1) dst(4,1); dst(1,2) dst(2,2) dst(3,2) dst(4,2); ...dst(1,1)*dst(1,2) dst(2,1)*dst(2,2) dst(3,1)*dst(3,2) dst(4,1)*dst(4,2); 1 1 1 1];
b = [point(1,1) point(2,1) point(3,1) point(4,1); point(1,2) point(2,2) point(3,2) point(4,2)];
T = b*inv(a);
%变换
newrow = point(2,3);
newimg = ones(newrow,newcol)*255;
for i = 1:newrowfor j = 1:newcolt = round(T*[i; j; i*j; 1]);if t(1) > 0 && t(1) <= row && t(2) > 0 && t(2) <= colnewimg(i,j)=img(t(1),t(2));endend
end
%figure;imshow(newimg);title('双线性变换');
%判断左右是否颠倒
%左边第一个黑色块的长度
trow = round(newrow/2);
startlen = 0;
for j = 1:newcolif newimg(trow,j) == 0while newimg(trow,j) == 0j=j+1;startlen = startlen + 1;endbreak;end
end
%右边第一个黑色块的长度
endlen = 0;
for j = newcol:-1:1if newimg(trow,j) == 0while newimg(trow,j) == 0j=j-1;endlen = endlen + 1;endbreak;end
end
%判断是否左右颠倒,比较左边第一个黑色块的长度和右边第一个黑色块的长度,若右边的更长,说明左右颠倒
%旋转180度
if startlen < endlennewimg(:,1:newcol) = newimg(:,newcol:-1:1);
end

邻近插值

功能: 去除变换过后二维码中的大量毛刺及白点

思路: 如果该点的水平或垂直方向上的邻近点与该点的灰度值不同,则把该点的灰度值重新赋值为邻近点的值。

为去除白点做的修改:对水平或垂直方向上的较小的白色区间赋为黑色,水平阈值为2,竖直阈值为3时效果最佳。

function img=interpolate(img)
[row,col] = size(img);
%横向插值
for i=1:rowfor j=1:colif img(i,j) == 0tmp = j+1;%白色区间while tmp <= col && img(i,tmp) ~= 0tmp=tmp+1;endif tmp <= col && tmp-j <= 2  img(i,j+1:tmp-1)=0;endj = tmp - 1;endend
end
%纵向插值
for j=1:colfor i=1:rowif img(i,j) == 0tmp = i+1;while tmp <= row && img(tmp,j) ~= 0tmp=tmp+1;endif tmp <= row && tmp-i <= 3 img(i+1:tmp-1,j)=0;endi = tmp - 1;endend
end
end

主模块

close all;
clc;
%读取图像
img = imread('lv0 - relax.bmp');
figure;
imshow(img);title('原图');
%灰度图
if length(size(img)) == 3img = rgb2gray(img);
end
%二值化 形态学变换
img=Ostu(img);
figure;imshow(img),title('二值化');
I = connectdomin(img);  %去除多余连通域%膨胀
se=ones(3,3);
I1 = mdilate(I, se);
%截取二维码区域
mask = I1;
imb = (img&mask)*255;
imb = 255-imb;
figure;imshow(imb); title('截取');
%提取二维码边缘
im = I1-I;
figure;
imshow(im);title('边缘');
%通过边缘获取四个顶点
[x,y] = Hough(im);
%显示顶点
figure;
imshow(img);hold on;
plot(x(1),y(1),'Marker','o','Color','red'); hold on;
plot(x(2),y(2),'Marker','o','Color','green'); hold on;
plot(x(3),y(3),'Marker','o','Color','blue'); hold on;
plot(x(4),y(4),'Marker','o','Color','yellow'); hold on;
%双线性变换
newimg = bilinear_transform(imb, x, y);
figure;
imshow(newimg);title('双线性变换');
%邻近插值
newimg = interpolate(newimg);
figure;
imshow(newimg);title('邻近插值');

效果演示

  • 原图
  • OSTU
    • 二值化:前景像素为白色255,背景像素为黑色0
  • 形态学变换去除多余连通域
    • 重构出的与边界相连的连通域
    • 去除与边界相连的连通域
    • 开运算,去除极小的连通域
    • 闭运算,将二维码揉成一个连通域
    • 去除小于最大连通域一半的连通域
  • 形态学腐蚀膨胀获取边界
  • Hough变换
    • 累加数组Hr的surf图
    • 累加数组Hc的surf图
    • 求出顶点并显示在原图
  • 双线性变换
  • 邻近插值

pdf417条码解码(上)——图像的预处理相关推荐

  1. TensorFlow图像数据预处理

    写在前面 在之前介绍的栗子中都是直接使用图像原始的像素矩阵.但是如果在输入前通过对图像的预处理,可以尽量避免模型收到无关因素的影响.在大部分图像识别问题中,通过图像预处理过程可以提高模型的准确率. 1 ...

  2. Aspose.BarCode已修复关于PDF417条码识别和生成的各种问题条码控件网

    Aspose.BarCode是由Aspose Pty Ltd所开发的一款功能强大,且稳健的条形码生成和条码识别组件,其使用托管的C#编写,能帮助开发者快速简便的向其Microsoft应用程序(WinF ...

  3. (二)对图像进行预处理(灰度化,二值化)

    对图像进行预处理(灰度化,二值化) 一.图像灰度化处理 图像灰度化是指每个像素只有一个采样颜色的图像,这类图像通常显示为从最暗黑色到最亮的白色的灰度. 灰度图像与黑白图像不同,在计算机图像领域中黑白图 ...

  4. Java条码解码zxing

    问题: 目录 问题 ​编辑分析定位 解决实现 总结与反思 近期有网友做了一个系统,实现文档的拍照扫描,打印的文档上面有一个条码,但通过拍照设备拍照上传后发现无法识读其中的条码,网友也使用了zxing进 ...

  5. ffmpeg解码后图像呈绿色

    / 偶然发现 网站: 智城 让外包更简单~   有类似项目需求,可参考 http://www.taskcity.com/pages/search_projects_advance?keywords=& ...

  6. 图片情感分析(1):图像数据预处理

    图片情感分析,重点是颜色特征的提取,将每一个像素点的颜色特征转换成一个值,最终效果是把一个图片转换成一个二维矩阵,矩阵中每一个值都代表该像素点的颜色特征.概括来说就是将每个像素点的RGB值转换为HSV ...

  7. 卷积神经网络图像尺寸预处理-----图像裁剪

    在全卷积网络(FCN)中可以输入任意大小的图像尺寸,但卷积网络(CNN)中就不是这样了,在CNN是有卷积层和全连接层.首先我们知道卷积层对输入的图像尺寸是没有限制的,而全连接层就对输入的图像像有要求了 ...

  8. 【办公软件应用】万彩办公大师教程丨PDF417条码生成工具

    关于万彩办公大师的PDF417条码生成工具 免费PDF417条码生成工具近在咫尺.3种条码类型,5种模式,8种安全级别可供自由组合,自定义PDF417条码,一键输出,即可获得格式为.bmp的条码图片. ...

  9. 图像数据预处理(上)

    概要 数据预处理在众多深度学习算法中都起着重要作用,实际情况中,将数据做归一化和白化处理后,很多算法能够发挥最佳效果.然而除非对这些算法有丰富的使用经验,否则预处理的精确参数并非显而易见.在本页中,我 ...

最新文章

  1. MySQL进阶SQL优化
  2. iOS Xcode8的适配
  3. Stanford UFLDL教程 矢量化编程
  4. C语言unit test单元测试类的实现(附完整源码)
  5. java servlet jsp javabean关系图_Servlet+JSP+JavaBean开发模式(MVC)介绍
  6. Python在cmd中配置虚拟环境ERROR: Command errored out with exit status 1:
  7. nlp 财务提取_RPA,智慧财务时代的“珍妮纺织机”来了?
  8. 2020-09-01
  9. mysql时间段以后_mysql时间段查询
  10. 用socket来代替HttpWebRequest和HttpWebResponse
  11. apache-ab并发负载压力测试(转)
  12. JAVA class汉化工具hhclass v1.0免费版
  13. 格力分红55亿,董明珠能拿多少?
  14. 相干性(Coherence)和相关性(Correlation)的区别和联系
  15. java模拟新浪微博用户注册
  16. 15+ Javascript 中的数组方法
  17. bandgap中简并点理解与仿真
  18. Python 圆的周长和面积计算
  19. linux 磁盘碎片整理
  20. 5G NR PDCP协议(一)

热门文章

  1. matlab基础知识入门学习
  2. Eclipse 安装反编译插件jadclipse
  3. 银行面试十大得分要点(一)
  4. 蓝桥杯 基础练习全解 答案+解析 共17题 python
  5. 矩阵乘法和逆矩阵-线性代数课时3(MIT Linear Algebra , Gilbert Strang)
  6. SSH框架之Maven
  7. 游戏设计艺术 第2版 读书笔记(完)
  8. 耗时两个月开发的弯管机三维模型自动转档软件
  9. 揭密X86架构C可变参数函数实现原理
  10. 数据挖掘-实战记录(一)糖尿病python数据挖掘及其分析