pdf417条码解码(下)——译码
来源:互联网 发布:通信工程用什么软件 编辑:程序博客网 时间:2024/05/18 01:57
解码须知
- 符号字符的结构
- 符号字符的簇
三种译码模式
文本
- 大写字母型模式
- 小写字母型模式
- 混合型子模式
- 标点型子模式
子模式的设置是为了更有效的表示数据,每组子模式选择了文件中出现频率较高的一组字符集。在子模式中,每一个字符对应一个基为30的值(0~29),因此一个码字可以表示一个字符对。
码字=30*H+L任何模式到文本压缩模式的锁定都是到大写字母型子模式的锁定。
在一个子模式转移符后不接另一个子模式转移或锁定。
- 字节
- 数字
分组:将每15个码字从左到右分为一组(每15个码字可转换成44个数字位),其最后一组码字可小于15个。
对于每一组码字:先执行基900到基10的转换,再去掉前导位1.
转移和锁定
- 模式 锁定: 码字用于将当前模式切换为指定的目标模式,该模式在下一个切换前一直有效。
- 模式 转移: 码字用于将文本压缩模式暂时切换切换为字节压缩,这种切换仅对切换后的第一个码字有效,随后的码字又返回文本压缩的当前子模式。
pdf417条码参考资料及码字表自取
步骤
码字提取
功能描述:
提取图像边缘,从水平边缘可以得到层数,从竖直边缘可以得到条空长度;通过查对应簇的码字表得到码字
设计思路:
- 选用边缘检测算子sobel,使用其水平方向掩码和竖直方向掩码对图像滤波可分别得到水平边缘和竖直边缘。
- 图像中层与层之间的边界都会在水平投影图上形成明显的峰值,峰值的中点就是层的中心
- 竖直边缘包含了每个条空的长度信息,即每一层每两条竖线间的距离,记录到code中
- 起始符的长是17个模块,最前面黑色块长是8个模块,矩阵code中第一列的像素点数除以8即为一个模块的长度aunit
- Code数组点除以aunit,四舍五入后就能等得到期望的符号码字
- Pdf417每一行的簇按0,3,6依次排列,查对应簇的码字表得到码字
function str=mydecode(filepath)%读取图像img = imread(filepath);if(length(size(img)))==3 img = rgb2gray(img);end[row,col] = size(img);img = double(img);%figure; imshow(img);title('原图');%边缘检测topso = [-1 -2 -1;0 0 0;1 2 1];lefso = [-1 0 1;-2 0 2;-1 0 1];bx = abs(imfilter(img,topso));by = abs(imfilter(img,lefso));horizontal=(bx~=0)*255; %二值化 值不为0说明为边缘,设为255.vertical=(by~=0)*255;%figure; imshow(horizontal);title('水平边缘');%figure; imshow(vertical);title('竖直边缘');%寻找峰值line(1) = 1;k = 1;for i=3:row-2 %由于边缘的宽度为2个像素,所以不能判断该行i与邻行i-1、i+1的大小 if sum(horizontal(i,:)) > sum(horizontal(i-2,:)) && sum(horizontal(i,:)) > sum(horizontal(i-3,:))... && sum(horizontal(i,:)) > sum(horizontal(i+2,:)) && sum(horizontal(i,:)) > sum(horizontal(i+3,:)) k = k+1; line(k) = i; %且需要去除邻近行的干扰,将其设为0 horizontal(i-1:i+1,:) = 0; %排除干扰 endendk = k+1;line(k) = row;%每层中心Layers = floor( (line(1:k-1)+line(2:k))/2 );%遍历竖直边缘图vertical每一层中心行,遍历到竖线时记录此像素和上一个记录点的距离,即一个模块的长度%记录每个条空长度codes = zeros(k-1, col);len = 0;for i=1:k-1 last = 1; m = 0; for j=2:col-1 if vertical(Layers(i),j)==255 m = m+1; codes(i,m) = j-last; last = j; %由于边缘的宽度为2个像素,需要去除邻近列的干扰,将其设为0 vertical(Layers(i),j-1:j+1)=0; %排除干扰 end end m = m+1; codes(i,m) = col-last; if len < m len = m; %各行最大的有效点长度 endend%只取有效长度1到len,去除零向量codes = codes(:,1:len);%计算矩阵code中第一列的平均值,除以8,四舍五入后即为一个模块的长度aunitauint = sum(codes(:,1))/length(codes(:,1))/8;%code数组点除以aunit,四舍五入后就能得到期望的符号码字codes = round(codes/auint);%矩阵code中,前17列和后17列不携带码字,可以除去codes = codes(:,17:len-17);%遍历矩阵code,每从(i,j)处取8个数,使用find由8位数字查对应簇(i-1)%3+1的码字表得到码字[r,c] = size(codes);l = ceil(c/8);decodes = zeros(1,r*l);load symcodes.mat -ASCII;for i = 1:r for j =1:8:c temp = sum(codes(i,j:j+7).*(10.^(8-(1:8)))); decodes((i-1)*l+ceil(j/8)) = find(symcodes(mod((i-1),3)+1,:) == temp) - 1; endend
文本、数字压缩模式译码
功能描述:根据码字判断文本、数字压缩模式的锁定和转移,在对应模式下完成码字的译码。
设计思路:
- 数据区中的第一个码字是符号长度值。
- 根据码字判断文本、数字、压缩模式的锁定和转移,使用mode记录当前的解码模式 ,数字型:2,字节型:3, 文本大写模式:11,文本小写:12,文本混合:13,文本标点:14
- 使用premode用于转移模式时记录模式值,第一个表示当前是否为转移模式,第二个表示要返回的模式值
- 根据码字表,建立文本模式下各子模式下的对应字符表,tcbyte记录文本模式时的高低位数据,第一个值表示高位,第二个表示低位。
- 数字压缩模式将每15个码字从左到右分为一组,其最后一组码字可小于15个。对于每一组码字,先执行基900到基10的转换,再去掉前导位。用valueindex记录字节模式和数字模式的缓存序列,其中第一个值表示序列是否有效及何种模式 ,无效 0,数字模式1, 字节模式 2, 第二个值表示序列起始位置。
%字节模式未实现tc_uc = [65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,32,201,202,204];%大写字母模式tc_lc = [97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,32,205,202,204];%小写字母模式tc_mi = [48,49,50,51,52,53,54,55,56,57,38,13,09,44,58,35,45,46,36,47,43,37,42,61,94,203,32,201,200,204];%混合型模式tc_do = [59,60,62,64,91,92,93,95,96,126,33,13,09,44,58,10,45,46,36,47,34,124,42,40,41,63,123,125,39,200];%标点型模式codelen = decodes(1); %待解码码字长度mode = 11; %2->数字型、3->字节型、11->文本模式大写型、12->文本模式小写型、13->文本模式混合型、14->文本模式标点型premode = [0,0]; %用于转移模式时记录模式值,第一个值表示当前是否为转移模式,第二个值表示要返回的模式值tcbyte = zeros(1,2); %用于记录文本模式时的高低位数据,第一个值表示高位数据,第二个值表示低位数据valueindex = [0,0]; %用于记录字节模式和数字模式的缓存序列,其中第一个值表示序列是否有效及何种模式0->无效、1->数字模式、2->字节模式,第二个值表示序列起始位置str = ''; %用来存放译码结果for i=2:codelen if decodes(i)>=900 %三种模式的锁定 if decodes(i)==900 mode = 11; elseif decodes(i)==902 mode = 2; elseif decodes(i)==901 || decodes(i)==924 || decodes(i)==913 mode = 3; end if valueindex(1)==1 %数字模式 caches = decodes(valueindex(2):(i-1)); %数字模式下的待解码码字 len = size(caches,2); for k=1:15:len curvalues = zeros(1,15); %用来存储15个码字 if (k+14)<len curvalues = caches(k:k+14); else %不足15个码字 curvalues(k+15-len:15) = caches(k:len); end longnum=0; for j=1:15 %使用sym以便存储更多位 longnum = longnum+curvalues(j)*sym(9^(15-j))*(100^(15-j)); end tempstr = char(longnum); %转为字符串 str = strcat(str, tempstr(2:end)); %去除第一位1 %disp(['数字模式',str]); end end valueindex = [0,0]; else if mode>10 %文本模式解码 tcbyte(1) = floor(decodes(i)/30); %高位 tcbyte(2) = mod(decodes(i),30); %低位 for j=1:2 if mode==11 %大写字母模式 if premode(1)==1 %转移模式 mode = premode(2); premode(1) = 0; end if tc_uc(tcbyte(j)+1)==201 %ll=201,锁定为小写字母模式 mode = 12; elseif tc_uc(tcbyte(j)+1)==202 %ml=202,锁定为混合模式 mode = 13; elseif tc_uc(tcbyte(j)+1)==204 %ps=204,转移为标点模式 premode(1) = 1; premode(2) = mode; mode = 14; else str = strcat(str,char(tc_uc(tcbyte(j)+1))); %disp(['大写字母模式',str]); end elseif mode==12 %小写字母模式 if premode(1)==1 mode = premode(2); premode(1) = 0; end if tc_lc(tcbyte(j)+1)==205 %as=205,转移为大写字母模式 premode(1) = 1; premode(2) = mode; mode = 11; elseif tc_lc(tcbyte(j)+1)==202 %ml=202,锁定为混合模式 mode = 13; elseif tc_lc(tcbyte(j)+1)==204 %ps=204,转移为标点模式 premode(1) = 1; premode(2) = mode; mode = 14; else str = strcat(str,char(tc_lc(tcbyte(j)+1))); %disp(['小写字母模式',str]); end elseif mode==13 %混合型 if premode(1)==1 mode = premode(2); premode(1) = 0; end if tc_mi(tcbyte(j)+1)==200 %al=200,锁定为大写字母模式 mode = 11; elseif tc_mi(tcbyte(j)+1)==201 %ll=201,锁定为小写字母模式 mode = 12; elseif tc_mi(tcbyte(j)+1)==203 %pl=203,锁定为标点模式 mode = 14; elseif tc_mi(tcbyte(j)+1)==204 %ps=204,转移为标点模式 premode(1) = 1; premode(2) = mode; mode = 14; else str = strcat(str,char(tc_mi(tcbyte(j)+1))); %disp(['混合型',str]); end elseif mode==14 %标点 if premode(1)==1 mode = premode(2); premode(1) = 0; end if tc_do(tcbyte(j)+1)==200 %al=200,锁定为大写字母模式 mode = 11; else str = strcat(str,char(tc_do(tcbyte(j)+1))); %disp(['标点',str]); end end end elseif mode==2 %数字模式 if valueindex(1)==0 valueindex(1)=1; valueindex(2)=i; end elseif mode==3 %字节模式 if valueindex(1)==0 valueindex(1)=2; valueindex(2)=i; end end endend%disp(['解码后的数据为:',str])
测试结果
原图
sobel算子边缘提取
水平方向边缘
竖直方向边缘
找出每层中心
边界
共12层,每层中心如下
- 获取符号码字codes
截取出的数据块的符号码字,层数为12,列数为8*3=24 - 查表找出codes对应码字,12层,3个数据块,一共36个
- 最终译码结果
0 0
- pdf417条码解码(下)——译码
- pdf417条码解码(上)——图像的预处理
- 二维条码PDF417译码技术
- C++Builder下利用TImage制作二维条码PDF417打印控件(一)
- C++Builder下利用TImage制作二维条码PDF417打印控件(二)
- C++Builder下利用TImage制作二维条码PDF417打印控件(三)
- C++Builder下利用TImage制作二维条码PDF417打印控件(四)
- C++Builder下利用TImage制作二维条码PDF417打印控件(五)
- PDF417二维条码/二维码
- PDF417二维条码详解
- WINCE WM 下QR, DM, PDF417 二维码解码库
- PDF417二维条码技术简介
- PDF417二维条码技术简介
- PDF417码的二维码校正以及译码
- 条形码识别(3)——译码
- java decode(解码) encode(译码)
- 【教程】如何在C#中创建PDF417条码
- PDF417
- reflect包copy函数的使用
- Maven学习(四)创建java项目和web项目
- CMake 添加头文件目录,链接动态、静态库
- Angular JS页面传参的5种方式
- UITableView自动计算CELL高度
- pdf417条码解码(下)——译码
- 解决:java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
- javascript语法
- Hadoop浅解SnapShots
- AOP面向切面设计编程
- Codeforces 493D Vasya and Chess
- 2:00倒计时
- java排序(1):基本概念和各种排序的概述
- uvalive 6525——Attacking rooks(二分图匹配,好题!)