本文共 95805 字,大约阅读时间需要 319 分钟。
1)将256*256分辨率的图像变为128*128分辨率可以将源图像划分成2*2的子图像块,然后将2*2的
子图像块的所有像素颜色均按照F(i,j)的颜色值进行设定,达到降低分辨率的目的。
如:
F(i,j) F(i,j+1) F(i,j) F(i,j)
F(i+1,j) F(i+1,j+1) 变成 F(i,j) F(i,j)
(同理,256*256分辨率的图像变成64*64分辨率,只需要划分成4*4即可,以此类推。)
2) R单色, G单色,B单色化图像,只需要将图像的每一个像素中的相应的R, G, B值取出,然后利用类似
(R,R,R),(G,G,G),(B,B,B)的像素重新绘制即可。
3) 彩色图像的RGB和亮度Y,色差I,信号值Q的关系
| Y | |0.31 0.59 0.11 | | R |
| I | = |0.60 -0.28 -0.32 | * | G |
|Q | |0.21 -0.52 -0.31 | | B |
即 Y = 0.31R + 0.59G+0.11B
I = 0.60R - 0.28G - 0.32B
Q = 0.21R - 0.52B - 0.31B
4) 彩色图像的逆反处理: 将对应的(R, G, B)像素替换成(255 - R, 255 - G, 255 - B)
彩色图像的平滑处理: 将一个图片每一个像素的颜色由其相邻的n*n个像素的平均值来替代。例如,将一个3*3的点阵,设带平滑的像素为f(i, j),平滑后为g(i, j),那么
f(i-1,j-1) f(i-1,j) f(i-1,j+1)
f(i,j-1) f(i,j) f(i,j+1)
f(i+1,j-1) f(i+1,j) f(i+1,j+1)
g(i,j)=( f(i-1,j-1) + f(i-1,j) + f(i-1,j+1) + f(i,j-1) + f(i,j) + f(i,j+1) + f(i+1,j-1) + f(i+1,j) + f(i+1,j+1) ) / 9
这里要注意的是对于边缘的像素的情况,防止越界。
彩色图像的霓虹处理: 同样以上面的3*3的点阵为例,目标像素g(i,j)应当以f(i,j)与f(i,j+1),f(i,j)与f(i+1,j)的梯度作为R,G,B分量,我们不妨设f(i,j)的RGB分量为(r1, g1, b1), f(i,j+1)为(r2, g2, b2), f(i+1,j)为(r3, g3, b3), g(i, j)为(r, g, b),那么结果应该为
r = 2 * sqrt( (r1 - r2)^2 + (r1 - r3)^2 )
g = 2 * sqrt( (g1 - g2)^2 + (g1 - g3)^2 )
b = 2 * sqrt( (b1 - b2)^2 + (b1 - b3)^2 )
彩色图像的锐化处理: 设f(i,j)像素为(r1, g1, b1) , f(i-1,j-1)像素为(r2,g2,b2), g(i,j)像素为(r,g,b),则
r = r1 + 0.25 * |r1 - r2|
g = g1 + 0.25 * |g1 - g2|
b = b1 + 0.25 * |b1 - b2|
彩色图像的浮雕处理: g(i, j) = f(i, j) - f(i - 1, j) + 常数 , 这里的常数通常选作128
彩色图像的镶嵌处理: 与彩色图像的平滑处理类似,但是不同的地方在于3*3的目标像素点都取作g(i,j),而不是另外的再去取所在矩阵像素的平均值。
彩色图像的灰度处理: r = r1 / 64 * 64 g = g1 / 64 * 64 b = b1 / 64 * 64 注意这里的除法是程序设计当中的整数除法。
5) 图象的几何变换:平移,缩放,旋转等均于解析几何当中的保持一致。
6) 图象的滤波处理
● 卷积滤波 原理是 y(n1, n2)=∑∑x(m1,m2)h(n1-m1,n2-m2) (两个求和符号的范围分别是 m1:0~N m2:0~N)
其中x(m1,m2)为输入图像信号,h(n1-m1,n2-m2)为滤波系统对单位采样序列δ(n1,n2)的响应。
⊙低通滤波 一般而言,图像中的噪声频谱位于空间频率较高的区域,空间域低通滤波用于平滑噪声。常用低通滤波的
h(n1, n2) 的3*3阵列如下:
1/9 1/9 1/9
h(n1, n2) = 1/9 1/9 1/9
1/9 1/9 1/9
1/10 1/10 1/10
h(n1, n2) = 1/10 2/10 1/10
1/10 1/10 1/10
1/16 1/8 1/16
h(n1, n2) = 1/8 1/4 1/8
1/16 1/8 1/16
采用5*5阵列低通滤波h(n1,n2)如下:
1/35 1/35 1/35 1/35 1/35
1/35 2/35 2/35 2/35 1/35
h(n1, n2) = 1/35 2/35 3/35 2/35 1/35
1/35 2/35 2/35 2/35 1/35
1/35 1/35 1/35 1/35 1/35
⊙高通滤波 空域高通滤波是对图像的低频分量进行拟制,让图像的高频分量无损耗或者低损耗的通过。空域高通滤波常用的h(n1,n2)的如下:
0 -1 0
h(n1, n2) = -1 5 -1
0 -1 0
-1 -1 -1
h(n1, n2) = -1 9 -1
-1 -1 -1
1 -2 1
h(n1, n2) = -2 5 -2
0 -2 1
● 增强处理
⊙ 水平增强 增强图像水平方向线条也是一种高通滤波。水平增强的h(n1, n2)的例子如下:
0 0 0
h(n1, n2) = 0 0 0
-1 2 -1
⊙ 垂直增强 增强图像垂直方向线条也是一种高通滤波。水平增强的h(n1, n2)的例子如下:
-1 0 0
h(n1, n2) = 2 0 0
-1 0 0
⊙ 水平垂直增强 水平垂直增强图像也是一种高通滤波。水平增强的h(n1, n2)的例子如下:
-1 -1 -1
h(n1, n2) = -1 8 -1
-1 -1 -1
● 结构滤波
⊙ 并联型结构滤波
结构如图:
例如,当
0 0 0
h1(n1, n2) = 0 0 0
-1 2 -1
-1 0 0
h2(n1, n2) = 2 0 0
-1 0 0
则h(n1, n2)为
-1 0 0
h(n1, n2) = 2 0 0
-1 2 -1
⊙ 串联型结构滤波
结构如图:
例如,当
0 0 0
h1(n1, n2) = 0 0 0
-1 2 -1
-1 0 0
h2(n1, n2) = 2 0 0
-1 0 0
则h(n1, n2)为
1 -2 1
h(n1, n2) = -2 4 -2
1 -2 1
7) 图象的切换特效处理
● 上部和下部对接显示
只需要不断的同时描绘对称的上部和下部的一行像素即可
● 左部和右部对接显示
只需要不断的同时描绘对称的左部和右部的一列像素即可
● 四边向中央显示
只需要不断的同时等进阶的描绘四边直至描绘到中心点即可
● 中央向四边显示
只需要不断的从中心点同时等进阶的描绘四边直至描绘到边缘即可
● 四角向中心显示
从左上角,右下角分别同时沿着主对角线等进阶的描绘自己所在像素的行,列像素直至中心
● 水平删条
设定分割长度L, 然后分别从高度为L, 2L, 3L ... 处等进阶的描绘行像素,显然这里进阶所需描绘高度为L
● 垂直删条
设定分割长度L, 然后分别从宽度为L, 2L, 3L ... 处等进阶的描绘列像素,显然这里进阶所需描绘宽度为L
● 由左向右(由右向左)
分别从左至右(从右至左)不断的描绘列像素直至边缘
● 由上向下(由下向上)
分别由上向下(由下向上)不断的描绘行像素直至边缘
8) 边缘探测
在图像测量,模式识别时,从图像中抽出线条,检测出图像边缘或者抽出图像轮廓是最常用的操作。迄今为止,已经出现了许多成熟的算法。例如微分算法,掩模算法等。在微分算法中,常使用N*N的像素块,例如3*3或者4*4。3*3的像素块如下,
f(i-1,j-1) f(i-1,j) f(i-1,j+1)
f(i,j-1) f(i,j) f(i,j+1)
f(i+1,j-1) f(i+1,j) f(i+1,j+1)
我们不妨设f(i,j)为待处理的像素,而g(i, j)为处理后的像素。
● Roberts算子
g(i, j) = sqrt( (f(i, j) - f(i + 1, j))^2 + (f(i + 1, j) - f(i, j + 1))^2 )
或者
g(i, j) = |f(i,j) - f(i + 1,j)| + |f(i+1,j) - f(i,j+1)|
● Sobel算子
对数字图像的每一个像素f(i,j),考察它的上、下、左、右邻域灰度的加权值,把各方向上(0度、45度、90度、135度)的灰度值加权之和作为输出,可以达到提取图像边缘的效果。
即 g(i,j) = fxr + fyr, 其中
fxr = f(i-1,j-1)+2*f(i-1,j)+f(i-1,j+1)-f(i+1,j-1)-2*f(i+1,j)-f(i+1,j+1)
fyr = f(i-1,j-1)+2*f(i,j-1)+f(i+1,j-1)-f(i-1,j+1)-2*f(i,j+1)-f(i+1,j+1)
● Laplace算子
Laplace算子是一种二阶微分算子。它有两种形式:4邻域微分算子和8邻域微分算子。
⊙ 4邻域微分
g(i,j)=|4*f(i,j)-f(i,j-1)-f(i-1,j)-f(i+1,j)-f(i,j+1)|
⊙ 8邻域微分
g(i,j)=|8*f(i,j)-f(i,j-1)-f(i-1,j)-f(i+1,j)-f(i,j+1)-f(i-1,j-1)-f(i-1,j+1)-f(i+1,j-1)-f(i+1,j+1)|
● 其他常用算子
⊙ 右下边缘抽出
采用3*3算子时,表达式为
g(i,j)=|-2*f(i,j-1)-2*f(i-1,j)+2*f(i+1,j)+2*f(i,j+1)|
⊙ prewitt 边缘探测样板算子
prewitt算子是一个边缘模板算子,由八个方向的样板组成,能够在0度,45度,90度,135度,180度,225度角
等八个方向检测边缘。8个3*3边缘模板及方向如下:
90度角: 45度角:
1 1 1 -1 -1 -1
1 -2 1 1 -2 1
-1 -1 -1 1 1 1
0度角: 315度角:
-1 1 1 1 1 -1
-1 -2 1 1 -2 -1
-1 1 1 1 1 -1
270度角: 225度角:
1 1 1 -1 -1 1
-1 -2 1 -1 -2 1
-1 -1 1 1 1 1
180度角: 135度角:
1 1 1 1 -1 -1
1 -2 -1 1 -2 -1
1 -1 -1 1 1 1
3*3时表达式如下:
A1*f(i-1,j-1) A8*f(i,j-1) A7*f(i+1,j-1)
A2*f(i-1,j) -2*f(i,j) A6*f(i+1, j)
A3*f(i-1,j+1) A4*f(i,j+1) A5*f(i+1,j+1)
g(i,j)=|-2*f(i,j)+A8*f(i,j-1)+A1*f(i-1,j-1)+A2*f(i-1,j)+A3*f(i-1,j+1)+A4*f(i,j+1)+A5*f(i+1,j+1)+A6*f(i+1,j)+A7*f(i+1,j-1)|
在程序设计中,依次用样板去检测图像,与被检测区域最为相似的样板给出最大值,用该最大值作为算子的输出值。
⊙ Robinson算子
Robinson算子是一个模板算子,由八个方向的样板组成,能够在0度,45度,90度,135度,180度,225度角
等八个方向检测边缘。8个3*3边缘模板及方向如下:
90度角: 45度角:
1 2 1 0 1 2
0 0 0 -1 0 1
-1 -2 -1 -2 -1 0
0度角: 315度角:
-1 0 1 -2 -1 0
-2 0 2 -1 0 1
-1 0 1 0 1 2
270度角: 225度角:
-1 -2 -1 0 -1 -2
0 0 0 1 0 -1
1 2 1 2 1 0
180度角: 135度角:
1 0 -1 2 1 0
2 0 -2 1 0 -1
1 0 -1 0 -1 -2
使用方法与prewitt算子一样。
⊙ Kirsch算子
Kirsch算子是一个模板算子,由八个方向的边缘样板组成,能够在0度,45度,90度,135度,180度,225度角
等八个方向检测边缘。8个3*3边缘模板及方向如下:
90度角: 45度角:
5 5 5 -3 5 5
-3 0 -3 -3 0 5
-3 -3 -3 -3 -3 -3
0度角: 315度角:
-3 -3 5 -3 -3 -3
-3 0 5 -3 0 5
-3 -3 5 -3 5 5
270度角: 225度角:
5 5 -3 -3 -3 -3
5 0 -3 5 0 -3
-3 -3 -3 5 5 -3
180度角: 135度角:
5 -3 -3 5 5 -3
5 0 -3 5 0 -3
5 -3 -3 -3 -3 3
使用方法与prewitt算子一样。
⊙ Smoothed算子
Smoothed算子是一个3*3的算子,设
|-1 0 1| |1 1 1|
Dx = |-1 0 1| Dy = |0 0 0|
|-1 0 1| |-1 -1 -1|
则 D = sqrt(Dx^2 + Dy^2) 或者 D = |Dx| + |Dy|
或 Dx(i, j) = f(i-1,j+1)+f(i,j+1)+f(i+1,j+1)-f(i-1,j-1)-f(i,j-1)-f(i+1,j-1)
Dy(i,j) = f(i-1,j-1)+f(i-1,j)+f(i-1,j+1)-f(i+1,j-1)-f(i+1,j)-f(i+1,j+1)
9) 灰度图像处理
所谓灰度处理是根据单色图像的灰度对输出图像的灰度进行再定义、以改善图像的对比度。单色图像的灰度有256级、128级、64级等,下面均以256级单色图像举例。
我们不妨设源图像的灰度值为f(i,j),处理后的灰度值为g(i,j)
● 逆反处理
与彩色图像的逆反处理一样: g(i,j) = 255 - f(i,j)
● 灰度级切换
灰度级切换的输入、输出灰度值对应关系如下:
● 增大对比度
输入的灰度值越高,对应的输出灰度值越低。灰度值减少,图像变暗,从而使对比度增加。
● 减小对比度
● 改善对比度
● 增强对比度
● 局部滤波处理
局部滤波处理是指利用3*3的图像块内的像素的颜色值对当前像素进行设定的一种图像处理技术。
⊙ 平均值滤波
与彩色图像平滑处理类似。
g(i,j)=( f(i-1,j-1) + f(i-1,j) + f(i-1,j+1) + f(i,j-1) + f(i,j) + f(i,j+1) + f(i+1,j-1) + f(i+1,j) + f(i+1,j+1) ) / 9
这里要注意的是对于边缘的像素的情况,防止越界。
⊙ 最小值滤波
最小值滤波是指在图像中以当前像素f(i,j)为中心切出一个N*M(例如3*3)像素组成的图像块,g(i,j)取图像块中灰度值中的最小值
⊙ 最大值滤波
最大值滤波是指在图像中以当前像素f(i,j)为中心切出一个N*M(例如3*3)像素组成的图像块,g(i,j)取图像块中灰度值中的最大值
⊙ 中值滤波
中值滤波是指在图像中以当前像素f(i,j)为中心切出一个N*M(例如3*3)像素组成的图像块,g(i,j)取图像块中所有灰度排序后序列的中间值
10) 灰度图像处理
● 灰度图像的二值化
⊙ 灰度图像直方图
对于每个灰度值,求出在图像中具有该灰度值的像素数的图形叫做灰度直方图。。灰度直方图是灰度级的函数,描述图像中具有相同灰度像素的个数。灰度直方图的横坐标是灰度级,纵坐标是该灰度出现的频率(即像素的个数)。直方图的用途主要是给出了一个简单可见的指示,用来判断一幅图像是否合理的利用了全部被允许的灰度级范围。一般一幅数字图像应该利用全部或几乎全部可能的灰度级范围。一般一幅数字图像应该利用全部或几乎全部可能的灰度级,否则增加了量化间隔。一旦被数字化图像的级数小于255,丢失的信息将不能恢复。如果图像具有超出数字量化器所能处理的范围的亮度,则这些灰度级将简单的置为0或255,由此将在直方图的一端或两端产生尖峰。灰度图像直方图具有直方图的一些统计特征参量,包括了灰度最大值,灰度最小值,均值和标准差。
⊙ 阙值计算和图像二值化
图像二值化的阙值处理方式为:
g(i,j) = 1; f(i,j)>=t
g(i,j) = 0; f(i,j)<t
通常,用g(i,j)=1表示图像,用g(i,)=0表示背景。确定t的方法叫做阙值选择。
● 灰度图像的二值化算法
⊙ 类判别法寻找阙值的步骤:
(1) 计算输入图像的灰度级直方图(用灰度级的概率函数PHS(i)来表示)
(2) 计算灰度均值(Ave) Ave = sigma((i - 1)*Phs(i)) i: 0->255
(3) 计算灰度类均值(Aver(k))和类直方图和(W(k))
Aver(k) = sigma((i+1)*Phs(i)) i: 0->k
W(k) = sigma(Phs(i)) i: 1->k
(4)计算类分离指标
Q(k)={[Ave*W(k)-Aver(k)]^2)}/[W(k)*(1-W(k))]}
(5) 求使Q最大的k 最佳阙值: T = k - 1
⊙ 灰度级切片法
将输入图像的某一灰度级范围内的所有像素全部置为0(黑),其余灰度级的所有像素全部置为255(白),则生成黑白
二值图像。
⊙ 等灰度片二值化
将输入图像在某两个等宽的灰度级范围内的所有像素全部置为0(黑),其余灰度级的所有像素全部置为255(白),则生成黑白二值图像。
⊙ 线性二值化
将输入图像在某一灰度级内的所有像素全部置为0(黑),其余灰度级的所有像素全部置为原值的1/2,则生成黑白二值图像,并将图像与背景分离。
● 二值图像处理
二值图像处理是指将二值化的图像进行某种修正,使之更适合于图像测量。二值图像处理包括以下操作:
膨胀 使粒子变大。对图像进行膨胀处理之后再进行收缩处理,则可以修正图像的凹槽
收缩 使粒子变小。对图像进行收缩处理之后再进行膨胀处理,则可以修正图像的凸槽
清除孤立点 清除由一个像素构成的对象以及修正由一个像素构成的孔。
清除粒子 清除任意面积以下的对象
清除超大粒子 清除任意面积以上的对象
洞穴填充 填充任意范围
⊙ 4邻域收缩
4邻域收缩的原理是,在3*3的图像块中,如果当前处理像素f(i,j)为0,则其相邻的像素f(i,j+1),f(i,j-1),f(i-1,j),f(i+1,j)均置255。
⊙ 8邻域收缩
8邻域收缩的原理是,在3*3的图像块中,如果当前处理像素f(i,j)为0,则其相邻的像素f(i,j+1),f(i,j-1),f(i-1,j),f(i+1,j),f(i-1,j-1),f(i+1,j-1),f(i-1,j+1),f(i+1,j+1)均置255。
⊙ 4邻域膨胀
4邻域膨胀的原理是,在3*3的图像块中,如果当前处理像素f(i,j)为1,则其相邻的像素f(i,j+1),f(i,j-1),f(i-1,j),f(i+1,j)均置1。
⊙ 8邻域膨胀
8邻域膨胀的原理是,在3*3的图像块中,如果当前处理像素f(i,j)为1,则其相邻的像素f(i,j+1),f(i,j-1),f(i-1,j),f(i+1,j),f(i-1,j-1),f(i+1,j-1),f(i-1,j+1),f(i+1,j+1)均置1。
⊙ 8邻域清除孤立点
8邻域清除孤立点的原理是,在3*3的图像块中,如果当前处理像素f(i,j)为1,而其相邻的像素f(i,j+1),f(i,j-1),f(i-1,j),f(i+1,j),f(i-1,j-1),f(i+1,j-1),f(i-1,j+1),f(i+1,j+1)均为0时,当前处理像素f(i,j)为0。
⊙ 4邻域清除孤立点
4邻域清除孤立点的原理是,在3*3的图像块中,如果当前处理像素f(i,j)为1,而其相邻的像素f(i,j+1),f(i,j-1),f(i-1,j),f(i+1,j均为0时,当前处理像素f(i,j)为0。
//实现
一、基本实现如下功能:
1) 图像灰度图、彩色图和二值化三种格式文件的打开和存储功能;
2) 支持版面局部纠偏功能;
3) 图像去污功能;
4) 支持图像局部浓淡调整功能;
5) 支持去除图像黑白边功能;
6) 支持部分磨白功能;
7) 擦除图像功能;
8) 自动和人工二值化功能;
9) 对图像提供横、竖拆页功能,图像人工、自动拼页功能;
10) 图像进行左、右旋转,翻转及改变图像亮度操作功能;
二、主函数为CArdpsImg类
1)头文件#pragma once
#include "api/dibapi.h" #include "api/ImgConv.h" #include "api/CompConnect.h" class CArdpsImg : public CObject { DECLARE_SERIAL(CArdpsImg)public:
CArdpsImg(void); CArdpsImg &operator =(const CArdpsImg &ArdSrc); CArdpsImg(const CArdpsImg &ArdSrc);HANDLE LoadNonDibHandle(BOOL *bBmp, char* szImgFileName);
bool ConvertGray(int nMethod, UINT uiRWeight = 114, UINT uiGWeight = 587, UINT uiBWeight = 299 ); bool ConvertBinary(int nMethod /* = 0 */, int nTh /* = 0 */); bool SaveNonDIB(HDIB hDib, CString strFileName, ImageType nDestFileExtType ); bool GrayEqual(); bool GrayStretch(int nMethod, BYTE x1,BYTE y1,BYTE x2,BYTE y2); bool EliminateDirt(int nMethod, const CRect rct); bool EliminateDirt(int nMethod, const int nCircleX, const int nCircleY, const int nRadius); void SetDirtSize(CSize szMax, CSize szMin); CRect* GetDirtPos( int nMethod, int *nCnt); bool AutoEliminateDirt(int nMethod, int nMinArea); bool AutoEliminateDirt(int nMethod, CRect *pRect, int *pFlag, const int nNum); bool RotateImage(int iRotateAngle = 0); bool AutoRotatelImage( RECT rtROI); bool CutFrame(); bool SplitImage(POINT pt1, POINT pt2, CArdpsImg *pNewArd); bool MergeImage(CArdpsImg *pSrcArd, int nMethod = 0); bool MergeImage(CArdpsImg *pSrcArd, int nPos1, int nPos2, int nMethod = 0); bool SaveTiff(char *szImgFileName); bool AjustLightAndContrast(int brightness, int contrast); bool Zoom(double fRatioX, double fRatioY); bool AdjustBinPos( int nMethod = 0); bool ColorEqual(); bool SaveGrayDIB(); // for debugvoid Serialize(CArchive& ar); bool IsEmpty(); bool Read(CFile *pFile); bool Write(CFile *pFile); bool Create(LPBYTE lpDIB); bool Create(LPBYTE lpDIB, WORD wBitCount); bool UpdateInternal(); void Destroy(); bool BuildBitmap(); bool BuildPalette(); bool Display(CDC* pDC, int x, int y, DWORD dwRop=SRCCOPY); bool ConvertFormat(WORD wBitCount); WORD GetBitCount(); LONG GetWidth(); LONG GetHeight(); LONG GetWidthBytes(); WORD GetPaletteSize(); HANDLE GetHandle(); WORD GetColorNumber(); LPBYTE GetBitsPtr(); bool Attach(HDIB hDib); ImageType GetFileExtType(CString strExt); CPalette* GetPalette(); private: bool InitDIBFileHead(LPBITMAPINFOHEADER lpBI, BITMAPFILEHEADER *lpbmfHdr); bool IntensityMean(const BYTE *pbGray, const int nImgWid, const int nImgHei, int &nIntenMean ); bool ThreshImage(const BYTE *pbImg, BYTE *pbBinary, const int nImgWid, const int nImgHei, const int nTh); void OtsuTh( DWORD nW, DWORD nH, BYTE *lpBits, int &Th); void ExtractComponent(Line * Li, BYTE *pMotion, UINT grayBytesPerLine, BYTE bCur ) ; inline void add(int a,int b,char **flag,int *&stack,int **InStack, int &top,int &topin,int c,int d,component *ctail, BYTE *pMotion, UINT grayBytesPerLine, BYTE bCur ); void AnalysisComponent( Line * Li, BYTE *pbBinary, UINT unBinaryBytesPerLine, UINT minArea, const BYTE bValue); bool AnalysisDirtPos(Line *Li, CSize maxSize, CSize minSize, int nHeight, int *nCnt); bool ConvertBinary2Gray(const unsigned char * pbBinary, const int nWidth, const int nHeight, unsigned char *pbGray); void SetBinary(CRect rect, BYTE *pbImg, UINT unBinaryBytesPerLine, const BYTE bValue); int OutputNormalImageUnderAngle(BYTE *DesImg, const BYTE *SrcImage, int nWidth, int nHeight, double dk); bool FindTopEdge(BYTE *pbOutImage, BYTE *image, RECT rtROI, int nWidth); double DetectSkewAngle(BYTE *pbImage, RECT rtROI, int nWidth); RECT GetEdgeImageBoundary(BYTE *pbImage, int nWidth, int nHeight); RECT GetBinImageBoundary(BYTE *pbImage, int nWidth, int nHeight); int FindEdgeImage(BYTE *pbOutImage, BYTE *image, RECT rtROI, int nWidth); RECT SetRectValue(int left, int right, int top, int bottom); bool VerticalSplit(int nX, CArdpsImg *newArt); bool HorizntalSplit(int nY, CArdpsImg *newArt); int CompVPrjValeSum(int *pnRamBuff, const BYTE *pInImg, int nImgWidth, int nImgHeight, int nRotAngle); void SmoothingArray(int *pOut, int nR, const int *pIn, int nStart, int nEnd) ; int DeleteVtlSmallLine(BYTE* pImg, BYTE* pBuf, int nWidth, int nHeight, int nTh); HDIB ReadBinTiff(char* szImgFileName); void Img32to24(BYTE *pbImg32, BYTE *pbImg24, int nWidth, int nHeight); void ReversBits(BYTE *pbIn, int nWidth, int nHeight, DWORD nBitCnt); void ReversColors(BYTE*pbIn, BYTE *pbOut, int nWidth, int nHeight); void ReversColors(BYTE*pbIn, int nWidth, int nHeight); void MoveBin(BYTE *pbIn, int nWidth, int nHeight, RECT rtOld, RECT rtNew, int nMethod = 0);
public: HDIB m_hDib; //DIB handle of CDib object HBITMAP m_hBitmap; // handle of DIBSection CPalette* m_pPalette; //related to DIB's palette CPalette object CBitmap* m_pBitmap; //related to DDB's CBitmap object HDIB m_hNewDib;
// private member data
private: // for drawing in DIB CDC * m_pMemDC; CBitmap* m_pBitmapTmp; CPalette* m_pPaletteTmp; CSize m_DirtSize; CSize m_minDirtSize; CRect *m_dirRect;public:
virtual ~CArdpsImg(void); };
2)源文件
#include "StdAfx.h"
#include "ArdpsImg.h" #include "api/ImgConv.h" #include "api/CompConnect.h" #include "api/tiff/tiffio.h" #include <stdlib.h> #include <time.h> #include <math.h> #include <windowsx.h> // especially for GlobalAllocPtr
const UINT uiRWeight = 114;
const UINT uiGWeight = 587; const UINT uiBWeight = 299; #define PI 3.14159 //角度到弧度转化的宏 #define RADIAN(angle) ((angle)*PI/180.0)#define EDGE_STEP 4
DWORD buf[256];
double bufi[256], varience[256]; // 5. the cos value(*65536 or * (2**16)) with angle from 0 to 180 and the step is 1 const int g_nCos[180] = { 65536, 65526, 65496, 65446, 65376, 65286, 65176, 65047, 64898, 64729, 64540, 64331, 64103, 63856, 63589, 63302, 62997, 62672, 62328, 61965, 61583, 61183, 60763, 60326, 59870, 59395, 58903, 58393, 57864, 57319, 56755, 56175, 55577, 54963, 54331, 53683, 53019, 52339, 51643, 50931, 50203, 49460, 48702, 47930, 47142, 46340, 45525, 44695, 43852, 42995, 42125, 41243, 40347, 39440, 38521, 37589, 36647, 35693, 34728, 33753, 32768, 31772, 30767, 29752, 28729, 27696, 26655, 25606, 24550, 23486, 22414, 21336, 20251, 19160, 18064, 16961, 15854, 14742, 13625, 12504, 11380, 10252, 9120, 7986, 6850, 5711, 4571, 3429, 2287, 1143, 0, -1143, -2287, -3429, -4571, -5711, -6850, -7986, -9120, -10252, -11380, -12504, -13625, -14742, -15854, -16961, -18064, -19160, -20251, -21336, -22414, -23486, -24550, -25606, -26655, -27696, -28729, -29752, -30767, -31772, -32768, -33753, -34728, -35693, -36647, -37589, -38521, -39440, -40347, -41243, -42125, -42995, -43852, -44695, -45525, -46340, -47142, -47930, -48702, -49460, -50203, -50931, -51643, -52339, -53019, -53683, -54331, -54963, -55577, -56175, -56755, -57319, -57864, -58393, -58903, -59395, -59870, -60326, -60763, -61183, -61583, -61965, -62328, -62672, -62997, -63302, -63589, -63856, -64103, -64331, -64540, -64729, -64898, -65047, -65176, -65286, -65376, -65446, -65496, -65526 };// 6. the sin value(*65536 or * (2**16)) with angle from 0 to 180 and the step is 1
const int g_nSin[180] = { 0, 1143, 2287, 3429, 4571, 5711, 6850, 7986, 9120, 10252, 11380, 12504, 13625, 14742, 15854, 16961, 18064, 19160, 20251, 21336, 22414, 23486, 24550, 25606, 26655, 27696, 28729, 29752, 30767, 31772, 32768, 33753, 34728, 35693, 36647, 37589, 38521, 39440, 40347, 41243, 42125, 42995, 43852, 44695, 45525, 46340, 47142, 47930, 48702, 49460, 50203, 50931, 51643, 52339, 53019, 53683, 54331, 54963, 55577, 56175, 56755, 57319, 57864, 58393, 58903, 59395, 59870, 60326, 60763, 61183, 61583, 61965, 62328, 62672, 62997, 63302, 63589, 63856, 64103, 64331, 64540, 64729, 64898, 65047, 65176, 65286, 65376, 65446, 65496, 65526, 65536, 65526, 65496, 65446, 65376, 65286, 65176, 65047, 64898, 64729, 64540, 64331, 64103, 63856, 63589, 63302, 62997, 62672, 62328, 61965, 61583, 61183, 60763, 60326, 59870, 59395, 58903, 58393, 57864, 57319, 56755, 56175, 55577, 54963, 54331, 53683, 53019, 52339, 51643, 50931, 50203, 49460, 48702, 47930, 47142, 46340, 45525, 44695, 43852, 42995, 42125, 41243, 40347, 39440, 38521, 37589, 36647, 35693, 34728, 33753, 32768, 31772, 30767, 29752, 28729, 27696, 26655, 25606, 24550, 23486, 22414, 21336, 20251, 19160, 18064, 16961, 15854, 14742, 13625, 12504, 11380, 10252, 9120, 7986, 6850, 5711, 4571, 3429, 2287, 1143 };typedef bool (*PFN_ImageConvert)(const unsigned char * pSrcData, int nSrcDataLen, ImageType itSrcImageType,
unsigned char * * ppDestData, int * pnDestDataLen, ImageType itDestImageType); typedef bool (*PFN_ImageDelete)(unsigned char * * ppImageData);IMPLEMENT_SERIAL(CArdpsImg, CObject, 0)
CArdpsImg::CArdpsImg(void)
{ m_hDib = NULL; //CDib对象所表示的DIB句柄 m_hBitmap = NULL; //DIB对应的DIBSECTION的句柄 m_pPalette = NULL; //和DIB相关的CPalette调色板对象 m_pBitmap = NULL; //和DIB相关的CBitmap DDB对象 m_hNewDib = NULL; m_DirtSize.cx = 5; m_DirtSize.cy = 5; m_minDirtSize.cx = 2; m_minDirtSize.cy = 2; m_dirRect = NULL; }CArdpsImg::CArdpsImg(const CArdpsImg &ArdSrc)
{ if (this != &ArdSrc) { Destroy(); if (m_pBitmap != NULL) { delete m_pBitmap; m_pBitmap = NULL; } if (m_pPalette != NULL) { delete m_pPalette; m_pPalette = NULL; } if( m_dirRect ) { delete []m_dirRect; m_dirRect = NULL; } if ( m_pMemDC ) { delete m_pMemDC; m_pMemDC = NULL; }this->m_hDib = ArdSrc.m_hDib;
this->m_hNewDib = ArdSrc.m_hNewDib; this->m_pBitmap = ArdSrc.m_pBitmap; this->m_pPalette = ArdSrc.m_pPalette; this->m_dirRect = ArdSrc.m_dirRect; this->m_pMemDC = ArdSrc.m_pMemDC; this->m_pPaletteTmp = ArdSrc.m_pPaletteTmp; this->m_pBitmapTmp = ArdSrc.m_pBitmapTmp; this->m_DirtSize = ArdSrc.m_DirtSize; this->m_minDirtSize = ArdSrc.m_minDirtSize; this->m_dirRect = ArdSrc.m_dirRect; } }CArdpsImg::~CArdpsImg(void)
{ Destroy(); if (m_pBitmap != NULL) { delete m_pBitmap; m_pBitmap = NULL; } if (m_pPalette != NULL) { delete m_pPalette; m_pPalette = NULL; } if( m_dirRect ) { delete []m_dirRect; m_dirRect = NULL; } }CArdpsImg & CArdpsImg::operator =(const CArdpsImg &ArdSrc)
{ if (this != &ArdSrc) { Destroy(); if (m_pBitmap != NULL) { delete m_pBitmap; m_pBitmap = NULL; } if (m_pPalette != NULL) { delete m_pPalette; m_pPalette = NULL; } if( m_dirRect ) { delete []m_dirRect; m_dirRect = NULL; } if ( m_pMemDC ) { delete m_pMemDC; m_pMemDC = NULL; }this->m_hDib = ArdSrc.m_hDib;
this->m_hNewDib = ArdSrc.m_hNewDib; this->m_pBitmap = ArdSrc.m_pBitmap; this->m_pPalette = ArdSrc.m_pPalette; this->m_dirRect = ArdSrc.m_dirRect; this->m_pMemDC = ArdSrc.m_pMemDC; this->m_pPaletteTmp = ArdSrc.m_pPaletteTmp; this->m_pBitmapTmp = ArdSrc.m_pBitmapTmp; this->m_DirtSize = ArdSrc.m_DirtSize; this->m_minDirtSize = ArdSrc.m_minDirtSize; this->m_dirRect = ArdSrc.m_dirRect; } return *this; } void CArdpsImg::Serialize(CArchive& ar) { CObject::Serialize(ar); ar.Flush(); if (ar.IsStoring()) { Write(ar.GetFile()); } else { Read(ar.GetFile()); } } bool CArdpsImg::Read(CFile *pFile) { WaitCursorBegin();LPBITMAPINFOHEADER lpbi;
DWORD dwSize; TRY { // read DIB file header BITMAPFILEHEADER bmfHdr; pFile->Read(&bmfHdr, sizeof(BITMAPFILEHEADER)); // is DIB file?if (bmfHdr.bfType != DIB_HEADER_MARKER/*"BM"*/)
{ WaitCursorEnd(); return false; } DWORD dwLength = pFile->GetLength(); if (bmfHdr.bfSize != dwLength) bmfHdr.bfSize = dwLength;// read DIB buffer
dwSize = bmfHdr.bfSize - sizeof(BITMAPFILEHEADER); lpbi = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, dwSize); DWORD dwCount = pFile->Read(lpbi, dwSize); // read ok? if (dwCount != dwSize) { GlobalFreePtr(lpbi); WaitCursorEnd(); return false; }// Check to see that it's a Windows DIB -- an OS/2 DIB would cause
// strange problems with the rest of the DIB API since the fields // in the header are different and the color table entries are // smaller. // // If it's not a Windows DIB (e.g. if biSize is wrong), return NULL. if (lpbi->biSize != sizeof(BITMAPINFOHEADER)) { GlobalFreePtr(lpbi); WaitCursorEnd(); return false; }// fill color num item
int nNumColors = (UINT)lpbi->biClrUsed; if (nNumColors == 0) { // no color table for 24-bit, default size otherwise if (lpbi->biBitCount != 24) nNumColors = 1 << lpbi->biBitCount; // standard size table }// fill in some default values if they are zero
if (lpbi->biClrUsed == 0) lpbi->biClrUsed = nNumColors; if (lpbi->biSizeImage == 0) lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3) * lpbi->biHeight; } CATCH (CException, e) { GlobalFreePtr(lpbi); WaitCursorEnd(); return false; } END_CATCH// create CDib with DIB buffer
bool bSuccess = Create((LPBYTE)lpbi); GlobalFreePtr(lpbi); WaitCursorEnd();return bSuccess;
} /// //从DIB数据块创建默认CDib对象 /// bool CArdpsImg::Create(LPBYTE lpDIB) { if (lpDIB == NULL) return false;DWORD dwSize = DIBlockSize(lpDIB);
HDIB hDib = GlobalAlloc(GHND, dwSize);
// Check that DIB handle is valid if (! hDib) return false;LPBYTE lpbi = (LPBYTE)GlobalLock(hDib);
if (! lpbi) return false;CopyMemory(lpbi, lpDIB, dwSize);
GlobalUnlock(hDib);Destroy();
m_hDib = hDib; LPBYTE ptmp = (LPBYTE) GlobalLock(m_hDib);return UpdateInternal();
} //******************************************************************* // 功能:调用DIBToDIBSection函数,创建并更新DIB的DIBSECTION和DDB //******************************************************************* bool CArdpsImg::BuildBitmap() { if (m_pBitmap != NULL) { delete m_pBitmap; m_pBitmap = NULL; m_hBitmap = NULL; } m_hBitmap = DIBToDIBSection(m_hDib); if (m_hBitmap == NULL) return false; m_pBitmap = new CBitmap; m_pBitmap->Attach(m_hBitmap);return true;
} //******************************************************************* //该函数调用CreateDIBPalette函数,创建并更新DIB调色板 //******************************************************************* bool CArdpsImg::BuildPalette() { if (m_pPalette != NULL) { delete m_pPalette; m_pPalette = NULL; } HPALETTE hPalette = CreateDIBPalette(m_hDib); if (hPalette == NULL) return false; m_pPalette = new CPalette; m_pPalette->Attach(hPalette);return true;
}//*******************************************************************
//UpdateInternal function 更新CDib对象所对应的调色板、DIBSECTION、DDB对象 //调用BuildPlaette 和BuildBitmap函数,重建CDib对象的,m_pPalette、m_hBitmap //和m_pBitmap 成员数据 bool CArdpsImg::UpdateInternal() { BuildPalette(); return BuildBitmap(); }void CArdpsImg::Destroy()
{ if (m_hDib != NULL) { DestroyDIB(m_hDib); m_hDib = NULL; } if( m_hNewDib != NULL ) { DestroyDIB(m_hNewDib); m_hNewDib = NULL; } } /// //从DIB数据块创建CDib对象 /// bool CArdpsImg::Create(LPBYTE lpDIB, WORD wBitCount) // bits/pixel { if (lpDIB == NULL) return false; if (! Create(lpDIB)) return false;WORD wBits = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
if (wBitCount == wBits) return true;HDIB hNewDib = ConvertDIBFormat(m_hDib, wBitCount, NULL);
if (! hNewDib) return false;Destroy();
m_hDib = hNewDib; return UpdateInternal(); } CPalette* CArdpsImg::GetPalette() { return m_pPalette; } bool CArdpsImg::Write(CFile *pFile) { WaitCursorBegin();BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure DWORD dwDIBSize;// Get a pointer to the DIB memory, the first of which contains
// a BITMAPINFO structure lpBI = (LPBITMAPINFOHEADER)GlobalLock(m_hDib); if (!lpBI) { GlobalUnlock(m_hDib); WaitCursorEnd(); return false; }// Check to see if we're dealing with an OS/2 DIB. If so, don't
// save it because our functions aren't written to deal with these // DIBs. if (lpBI->biSize != sizeof(BITMAPINFOHEADER)) { GlobalUnlock(m_hDib); WaitCursorEnd(); return false; }// Fill in the fields of the file header
// Fill in file type (first 2 bytes must be "BM" for a bitmap)
bmfHdr.bfType = DIB_HEADER_MARKER; // "BM"
// Calculating the size of the DIB is a bit tricky (if we want to
// do it right). The easiest way to do this is to call GlobalSize() // on our global handle, but since the size of our global memory may have // been padded a few bytes, we may end up writing out a few too // many bytes to the file (which may cause problems with some apps, // like HC 3.0). // // So, instead let's calculate the size manually. // // To do this, find size of header plus size of color table. Since the // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains // the size of the structure, let's use this.// Partial Calculation
dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPBYTE)lpBI);
// Now calculate the size of the image
// It's an RLE bitmap, we can't calculate size, so trust the biSizeImage
// fieldif ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
dwDIBSize += lpBI->biSizeImage; else { DWORD dwBmBitsSize; // Size of Bitmap Bits only// It's not RLE, so size is Width (DWORD aligned) * Height
dwBmBitsSize = MYWIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) *
lpBI->biHeight;dwDIBSize += dwBmBitsSize;
// Now, since we have calculated the correct size, why don't we
// fill in the biSizeImage field (this will fix any .BMP files which // have this field incorrect).lpBI->biSizeImage = dwBmBitsSize;
} // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0;// Now, calculate the offset the actual bitmap bits will be in
// the file -- It's the Bitmap file header plus the DIB header, // plus the size of the color table.bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
PaletteSize((LPBYTE)lpBI);TRY
{ // Write the file header pFile->Write(&bmfHdr, sizeof(BITMAPFILEHEADER)); // write DIB buffer pFile->Write(lpBI, dwDIBSize); } CATCH (CException, e) { GlobalUnlock(m_hDib); WaitCursorEnd(); return false; } END_CATCHGlobalUnlock(m_hDib);
WaitCursorEnd();return true;
} bool CArdpsImg::IsEmpty() { if (m_hDib == NULL) return true;if (! GlobalLock(m_hDib))
return true;GlobalUnlock(m_hDib);
return false; }bool CArdpsImg::Display(CDC * pDC, int x, int y, DWORD dwRop)
{ CDC MemDC; MemDC.CreateCompatibleDC(pDC);CBitmap* pOldBmp = MemDC.SelectObject(m_pBitmap);
CPalette* pOldPal = pDC->SelectPalette(m_pPalette, true);
pDC->RealizePalette();bool bSuccess = pDC->BitBlt(x, y,
GetWidth(), GetHeight(), &MemDC, 0, 0, dwRop);MemDC.SelectObject(pOldBmp);
pDC->SelectPalette(pOldPal, true);return bSuccess;
}WORD CArdpsImg::GetBitCount()
{ LPBITMAPINFOHEADER lpBI = (LPBITMAPINFOHEADER)GlobalLock(m_hDib); if (!lpBI) { GlobalUnlock(m_hDib); return 0; }WORD wBitCount = lpBI->biBitCount;
GlobalUnlock(m_hDib);return wBitCount;
}LONG CArdpsImg::GetWidth()
{ // get DIB buffer pointer LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); if (! lpDIB) { GlobalUnlock(m_hDib); return 0; }LONG lWidth = (LONG)DIBWidth(lpDIB);
GlobalUnlock(m_hDib);return lWidth;
}LONG CArdpsImg::GetHeight()
{ // get DIB buffer pointer LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); if (! lpDIB) { GlobalUnlock(m_hDib); return 0; }LONG lHeight = (LONG)DIBHeight(lpDIB);
GlobalUnlock(m_hDib);return lHeight;
}LONG CArdpsImg::GetWidthBytes()
{ return MYWIDTHBYTES((GetWidth())*((DWORD)GetBitCount())); //return WIDTHBYTES((GetWidth())*((int)GetBitCount())); } LPBYTE CArdpsImg::GetBitsPtr() { LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); if (! lpDIB) { GlobalUnlock(m_hDib); return NULL; }LPBYTE lpData = FindDIBBits(lpDIB);
GlobalUnlock(m_hDib);return lpData;
}HANDLE CArdpsImg::GetHandle()
{ return m_hDib; }WORD CArdpsImg::GetColorNumber()
{ LPBYTE lpBI = (LPBYTE)GlobalLock(m_hDib); if (! lpBI) { GlobalUnlock(m_hDib); return 0; }WORD wColors = DIBNumColors(lpBI);
GlobalUnlock(m_hDib);return wColors;
}WORD CArdpsImg::GetPaletteSize()
{ LPBYTE lpBI = (LPBYTE)GlobalLock(m_hDib); if (! lpBI) { GlobalUnlock(m_hDib); return 0; }WORD wPalSize = PaletteSize(lpBI);
GlobalUnlock(m_hDib);return wPalSize;
} bool CArdpsImg::Attach(HDIB hDib) { if (hDib == NULL) return false;Destroy();
m_hDib = hDib; return UpdateInternal(); } bool CArdpsImg::ConvertFormat(WORD wBitCount) { if (IsEmpty()) return false;if (GetBitCount() == wBitCount)
return true;HDIB hNewDib = ConvertDIBFormat(m_hDib, wBitCount, NULL);
if (! hNewDib) return false;Destroy();
m_hDib = hNewDib; return UpdateInternal(); } /* 功能:加载其他图像格式,支持jpg、tiff格式 输入: szImgFileName:文件名; 输出: bBmp:加载成功,转换成DIB句柄*/
HANDLE CArdpsImg::LoadNonDibHandle(BOOL *bBmp, char* szImgFileName)
{ *bBmp = FALSE; char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; char szName[256]; typedef HANDLE (WINAPI * PGETDIBPROC)(HWND, char *, HANDLE); PGETDIBPROC lpFun; HANDLE hDib;HINSTANCE hConvertLib = LoadLibrary("Convert.dll");
ASSERT(hConvertLib != NULL);strcpy(szName, szImgFileName);
_splitpath(szName, drive, dir, fname, ext); strcpy(szName, ext);strlwr(szName);
if(strcmp(szName,".tif") == 0 || strcmp(szName, ".tiff") == 0)
{ //lpFun = (PGETDIBPROC)GetProcAddress(hConvertLib, "Tiff2HDIB"); /*hDib = LoadTiff(szImgFileName);*/ hDib = ReadBinTiff(szImgFileName); return hDib; } else if(strcmp(szName,".jpg") == 0 || strcmp(szName,".jpeg") == 0 || strcmp(szName,".jpe") == 0 ) { lpFun = (PGETDIBPROC)GetProcAddress(hConvertLib, "Jpg2HDIB"); } else { if(hConvertLib) { FreeLibrary(hConvertLib); } *bBmp = TRUE;return NULL;
} ASSERT(lpFun != NULL); freopen("nul", "w", stdout);hDib = (*lpFun) ( NULL, szImgFileName, NULL);
freopen("con", "w", stdout);if(hConvertLib)
{ FreeLibrary(hConvertLib); }return hDib;
} /* 功能:BMP转换为其他图像格式 输入: hDib:当前图像句柄; strFileName:文件名; nDestFileExtType:在ImgConv.h中定义 输出: true:存储成功*/
bool CArdpsImg::SaveNonDIB(HDIB hDib, CString strFileName, ImageType nDestFileExtType) { HMODULE hDll = LoadLibrary("ImgConv.dll"); if (hDll == NULL) { return false; } PFN_ImageConvert ImageConvert = (PFN_ImageConvert)GetProcAddress(hDll, "ImageConvert"); PFN_ImageDelete ImageDelete = (PFN_ImageDelete)GetProcAddress(hDll, "ImageDelete"); if (ImageConvert == NULL || ImageDelete == NULL) { FreeLibrary(hDll); return false; } LPBITMAPINFOHEADER lpBI = (LPBITMAPINFOHEADER)GlobalLock(m_hDib); bool bSave = false; BITMAPFILEHEADER bmfHdr; bool bInit = InitDIBFileHead(lpBI, &bmfHdr); if( !bInit ) { GlobalUnlock(m_hDib); FreeLibrary(hDll); return false; }unsigned char *pbSrc = new unsigned char [bmfHdr.bfSize];
if( !pbSrc )
{ GlobalUnlock(m_hDib); FreeLibrary(hDll); return false; } memcpy(pbSrc, &bmfHdr, sizeof(BITMAPFILEHEADER)); memcpy(pbSrc + sizeof(BITMAPFILEHEADER), lpBI, lpBI->biSizeImage * sizeof(unsigned char));unsigned char * pDestData = NULL;
int nDestDataLen = 0; bool bSuccess = false; bSuccess = ImageConvert(pbSrc, bmfHdr.bfSize , imgBMP, &pDestData, &nDestDataLen, nDestFileExtType); if( bSuccess ) { FILE * pFile = fopen(strFileName, "wb"); if (pFile != NULL) { fwrite(pDestData, sizeof(unsigned char), nDestDataLen, pFile); fclose(pFile); ImageDelete(&pDestData); bSave = true; } } if (pbSrc) { delete []pbSrc; pbSrc = NULL; } FreeLibrary(hDll); GlobalUnlock(m_hDib); return bSave; } bool CArdpsImg::InitDIBFileHead(LPBITMAPINFOHEADER lpBI, BITMAPFILEHEADER *lpbmfHdr ) { if( !lpBI || !lpbmfHdr ) return false;//BITMAPFILEHEADER bmfHdr;
lpbmfHdr->bfType = DIB_HEADER_MARKER; // "BM" DWORD dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPBYTE)lpBI); if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4)) dwDIBSize += lpBI->biSizeImage; else { DWORD dwBmBitsSize; // Size of Bitmap Bits only// It's not RLE, so size is Width (DWORD aligned) * Height
dwBmBitsSize = MYWIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) *
lpBI->biHeight;dwDIBSize += dwBmBitsSize;
// Now, since we have calculated the correct size, why don't we
// fill in the biSizeImage field (this will fix any .BMP files which // have this field incorrect).lpBI->biSizeImage = dwBmBitsSize;
} lpbmfHdr->bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER); lpbmfHdr->bfReserved1 = 0; lpbmfHdr->bfReserved2 = 0; lpbmfHdr->bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize + PaletteSize((LPBYTE)lpBI); return true; }ImageType CArdpsImg::GetFileExtType(CString strExt)
{ if (strExt. CompareNoCase ("bmp") == 0 || strExt.CompareNoCase("dib") == 0 ) { return imgBMP; } else if (strExt.CompareNoCase("gif") == 0 ) { return imgGIF; } else if (strExt.CompareNoCase("jpg") == 0 ) { return imgJPG; } else if (strExt.CompareNoCase("jpeg") == 0 || strExt.CompareNoCase("jpe") == 0 ) { return imgJPEG; } else if (strExt.CompareNoCase("png") == 0 ) { return imgPNG; } else if (strExt.CompareNoCase("tiff") || strExt.CompareNoCase("tif")) { return imgTIFF; } else { return imgBMP; } } /* 功能:转换为灰度图像 输入: nMethod:二值化方法;默认为0,加权平均方法;1为最大值; uiGWeight,uiGWeight,uiBWeight:红、绿、蓝色分量 输出: true:灰度化成功*/
bool CArdpsImg::ConvertGray(int nMethod, UINT uiRWeight /* = 114 */, UINT uiGWeight /* = 587 */, UINT uiBWeight /* = 229 */) {LPBITMAPINFOHEADER lpDIBHdr = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);
//for color image LONG nImgHei = GetHeight(); LONG nImgWid = GetWidth(); LONG nOriBytesPerLine = GetWidthBytes(); int nBitCnt = GetBitCount(); if( nBitCnt < 24 ) { GlobalUnlock(m_hDib); return false; } //for gray image LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 ); LONG nGrayImgSize = nGrayBytesPerLine * nImgHei; LONG nFileSize = nGrayImgSize + lpDIBHdr->biSize + 256 * sizeof(RGBQUAD);//allocate memory for gray image
LPBYTE lpNewDIB = new BYTE[nFileSize]; if( !lpNewDIB ) { GlobalUnlock(m_hDib); return false; } memset(lpNewDIB, 0, nFileSize*sizeof(BYTE)); LPBITMAPINFOHEADER lpNewDIBHdr = (LPBITMAPINFOHEADER)lpNewDIB; memcpy(lpNewDIBHdr, lpDIBHdr, sizeof(BITMAPINFOHEADER)); GlobalUnlock(m_hDib);lpNewDIBHdr->biBitCount = 8;
lpNewDIBHdr->biCompression = BI_RGB; lpNewDIBHdr->biSizeImage = nGrayImgSize; lpNewDIBHdr->biClrUsed = 256; //create RGBQUARD RGBQUAD *pNewRGBQuad = (RGBQUAD*)(lpNewDIB +sizeof(BITMAPINFOHEADER));memset(pNewRGBQuad, 0, 256*sizeof(RGBQUAD));
for( int i = 0; i < 256; ++i ) { pNewRGBQuad->rgbBlue = pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = i; pNewRGBQuad++; }LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LPBYTE lpImg = FindDIBBits(lpDIB); LPBYTE lpNewImg = lpNewDIB + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);LPBYTE lpOritmp = lpImg;
LPBYTE lpNewtmp = lpNewImg; int j, k, m, n, nStep = nBitCnt >> 3; switch (nMethod) { case 0: for( j = 0, m = 0, n = 0; j < nImgHei; ++j , m += nOriBytesPerLine, n += nGrayBytesPerLine ) { lpNewtmp = lpNewImg + n; lpOritmp = lpImg + m; for( k = 0; k < nImgWid; ++k, lpNewtmp ++ ) { *lpNewtmp = BYTE(( (*lpOritmp) *uiRWeight + *(lpOritmp + 1) * uiGWeight + *(lpOritmp + 2) * uiBWeight )/1000); lpOritmp += nStep;}
} break; case 1: default: for( j = 0, m = 0, n = 0; j < nImgHei; ++j , m += nOriBytesPerLine, n += nGrayBytesPerLine ) { lpNewtmp = lpNewImg + n; lpOritmp = lpImg + m; for( k = 0; k < nImgWid; ++k, lpNewtmp ++ ) { *lpNewtmp = BYTE( max(max ( (*lpOritmp), *(lpOritmp + 1) ), *(lpOritmp + 2) )); lpOritmp += nStep; } } break; } GlobalUnlock(m_hDib); bool bCrate = Create(lpNewDIB); if( lpNewDIB ) { delete []lpNewDIB; lpNewDIB = NULL; }return true;
} /* 功能:对灰度图像进行二值化 输入: nMethod:二值化方法;默认为0,OTSU方法;1为均值;2:为给定阈值方法 nTh:二值化阈值 输出: true:二值化成功*/
bool CArdpsImg::ConvertBinary(int nMethod /* = 0 */, int nTh /* = 0 */) { //for image int nBitCnt = GetBitCount(); //for gray image LONG nGrayBytesPerLine = GetWidthBytes();if( nBitCnt > 8 )
{ bool bGray = ConvertGray(0); if(!bGray) { return false; } //lpDIBHdr = (LPBITMAPINFOHEADER)GlobalLock(m_hDib); } else if( nBitCnt == 1) { return true; }LPBITMAPINFOHEADER lpDIBHdr = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);
LONG nImgHei = GetHeight(); LONG nImgWid = GetWidth();//for binary image
LONG nBinaryBytesPerLine = MYWIDTHBYTES( nImgWid ); LONG nBinaryImgSize = nBinaryBytesPerLine * nImgHei; LONG nFileSize = nBinaryImgSize + lpDIBHdr->biSize + 2 * sizeof(RGBQUAD);//allocate memory for binary image
LPBYTE lpNewDIB = new BYTE[nFileSize]; if( !lpNewDIB ) { GlobalUnlock(m_hDib); return false; } memset(lpNewDIB, 0, nFileSize*sizeof(BYTE)); LPBITMAPINFOHEADER lpNewDIBHdr = (LPBITMAPINFOHEADER)lpNewDIB; memcpy(lpNewDIBHdr, lpDIBHdr, sizeof(BITMAPINFOHEADER)); GlobalUnlock(m_hDib);lpNewDIBHdr->biBitCount = 1;
lpNewDIBHdr->biCompression = 0; lpNewDIBHdr->biSizeImage = nBinaryImgSize; lpNewDIBHdr->biClrUsed = 2; lpNewDIBHdr->biXPelsPerMeter = 0; lpNewDIBHdr->biYPelsPerMeter = 0;//create RGBQUARD
RGBQUAD *pNewRGBQuad = (RGBQUAD*)(lpNewDIB +sizeof(BITMAPINFOHEADER));pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue
= 0; pNewRGBQuad->rgbReserved = 0; pNewRGBQuad++; pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue = 255; pNewRGBQuad->rgbReserved = 0; LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); LPBYTE lpImg = FindDIBBits(lpDIB); LPBYTE lpNewImg = lpNewDIB + sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD);LPBYTE lpOritmp = lpImg;
LPBYTE lpNewtmp = lpNewImg; int nStep = nBitCnt >> 3; bool bResult = false; switch (nMethod) { case 1: nTh = 0; bResult = IntensityMean( lpImg, nImgWid, nImgHei, nTh ); break; case 2: bResult = true; break; case 0: default: nTh = 0; OtsuTh(nImgWid, nImgHei, lpImg, nTh); bResult = true; break; } if( bResult ) bResult = ThreshImage(lpImg, lpNewImg, nImgWid, nImgHei, nTh);GlobalUnlock(m_hDib);
bool bCrate = Create(lpNewDIB); if (lpNewDIB) { delete []lpNewDIB; lpNewDIB = NULL; }return bCrate;
} /* 功能:利用Otsu方法计算二值化的阈值 输入: lpBits:灰度图像内存指针 nW:图像宽度 nH:图像高度 输出: Th:图像灰度均值 */ void CArdpsImg:: OtsuTh( DWORD nW, DWORD nH, BYTE *lpBits, int &Th) { UINT i; float bmax; float counter1,counter2; float mean1,mean2; int TH, threshold, k, deta; float sum1,sum2; int buf[256]; memset(buf, 0, 256 * sizeof(int)); if( !GetGrayHist(lpBits, nW, nH, buf) ) return;for ( i = 0; i < 256; i ++)
{ bufi[i] = i * buf[i]; }deta = 10; //计算阈值的步长,以加快求解速度。
counter1 = 0; for ( TH = 0; TH < 256; TH += deta ) { counter1 = counter2=0; sum1 = sum2=0.0; for( k = 0; k <= TH; k++ ) { counter1 += buf[k]; sum1 += bufi[k]; } for( k = TH + 1; k < 256; k++ ) { counter2 += buf[k]; sum2 += bufi[k]; } if ( counter1>0 ) mean1= sum1/counter1; else mean1=0; if ( counter2>0 ) mean2= sum2/counter2; else mean2=0; varience[TH]=counter1*counter2*(mean1-mean2)*(mean1-mean2); } bmax=varience[0]; threshold=0; for ( TH=0; TH<256; TH += deta ) { if( bmax<varience[TH] ) { bmax=varience[TH]; threshold=TH; } }Th=threshold;
}/*
功能:计算图像的灰度均值 输入: pbGray:灰度图像内存指针 nImgWid:图像宽度 nImgHei:图像高度 输出: nIntenMean:图像灰度均值 */ bool CArdpsImg::IntensityMean(const BYTE *pbGray, const int nImgWid, const int nImgHei, int &nIntenMean ) { if( pbGray == NULL || nImgHei <= 0 || nImgWid <= 0 ) return false; int nSum = 0; nIntenMean = 0; for( int i = 0; i < nImgHei * nImgWid; i++ ) { nSum += *pbGray ++; } nIntenMean = BYTE(nSum /((nImgHei * nImgWid) + 1)); return true; }bool CArdpsImg::ThreshImage(const BYTE *pbImg, BYTE *pbBinary, const int nImgWid, const int nImgHei, const int nTh )
{ if( pbImg == NULL || pbBinary== NULL ) return false; LONG nGrayPerLine = MYWIDTHBYTES(nImgWid << 3); LONG nBinaryPerLine = MYWIDTHBYTES(nImgWid);const BYTE *pbIn = pbImg;
BYTE *pbOut = pbBinary; BYTE tmp = 0; for( int i = 0, m = 0, n = 0; i < nImgHei; ++i ) { pbIn = pbImg + m; pbOut = pbBinary + n; for(int j = 0; j < nImgWid/8; ++j ) { tmp = 0; if( *pbIn > nTh ) tmp = tmp | 128; ++pbIn; if( *pbIn > nTh ) tmp = tmp | 64; ++pbIn; if( *pbIn > nTh ) tmp = tmp | 32; ++pbIn; if( *pbIn > nTh ) tmp = tmp | 16; ++pbIn; if( *pbIn > nTh ) tmp = tmp | 8; ++pbIn; if( *pbIn > nTh ) tmp = tmp | 4; ++pbIn; if( *pbIn > nTh ) tmp = tmp | 2; ++pbIn; if( *pbIn > nTh ) tmp = tmp | 1; ++pbIn;*pbOut ++ = tmp;
} tmp = 0; for( int k = 0; k < nImgWid % 8; k++, pbIn++ ) { if( *pbIn > nTh ) { tmp += 1; } tmp = tmp << 1; } *pbOut = tmp << (8 - nImgWid % 8 - 1); m += nGrayPerLine; n += nBinaryPerLine; }return true;
} /****************************************************************** 功能:灰度图像的均衡化,使得像素在灰度阶上尽量均匀 输入: 当前图像的内存句柄 输出: 灰度成功返回true ******************************************************************/ bool CArdpsImg::GrayEqual() { if(IsEmpty()) return false; if( !GrayEqualize(m_hDib)) return false; return UpdateInternal(); } /**************************************************************************** 功能:对灰度图像进行拉伸 输入: nMethod:灰度图像内存指针。 (x1,y1):拉伸曲线的第一点坐标 (x2,y2):拉伸曲线的第二点坐标 *(255,255) * * (x2,y2) * * * *(x1,y1) * *(0,0)nMethod = 0:根据直方图自动计算第一点和第二点坐标,阈值取累积直方图的10%~90%。
nMethod = 1:根据输入的坐标进行计算 输出: 操作成功返回True。 **********************************************************************************/ bool CArdpsImg::GrayStretch(int nMethod, BYTE x1 = 0 , BYTE y1 = 0 , BYTE x2 = 255, BYTE y2 = 255 ) { if(IsEmpty()) return false; if(!GrayStretchDIB(nMethod, m_hDib, x1, y1, x2, y2) ) return false; return UpdateInternal(); } /******************************************************************* 功能:去除矩形区域二值化图像的污点 输入: nMethod = 0:去污,选中区域如果为白色占主要部分则变成黑色 否则相反。 nMethod = 1 :磨白,把选中的区域变成白色 nMethod = 2:填充,把选中的区域变成黑色 rct:选中的处理区域 输出: 去除成功 *******************************************************************/ bool CArdpsImg::EliminateDirt(int nMethod, const CRect rct) { if ( rct.IsRectEmpty() || IsEmpty() ) return false; // Convert the physical coordinate into imaging coordinate if( GetBitCount() > 1 ) return false; if(!EliminateDirtDIB(nMethod, m_hDib, rct) ) return false; return UpdateInternal(); } /******************************************************************* 功能:去除圆形区域二值化图像的污点 输入: nMethod = 0:去污,选中区域如果为白色占主要部分则变成黑色 否则相反。 nMethod = 1 :磨白,把选中的区域变成白色 nMethod = 2:填充,把选中的区域变成黑色 rct:选中的处理区域 输出: 去除成功 *******************************************************************/ bool CArdpsImg::EliminateDirt(int nMethod, const int nCircleX, const int nCircleY, const int nRadius) { if( IsEmpty() || nCircleX < 0 || nCircleY < 0 || nRadius < 0 ) return false; if( GetBitCount() > 1 ) return false; if(!EliminateDirtDIB(nMethod, m_hDib, nCircleX, nCircleY, nRadius) ) return false;return UpdateInternal();
} /****************************************************************** 功能:设置污点的大小 输入: sz,污点大小,小于sz为污点 ******************************************************************/void CArdpsImg::SetDirtSize(CSize szMax, CSize szMin)
{ m_DirtSize = szMax; m_minDirtSize = szMin; }/******************************************************************
功能:自动去除图像中的小于一定面积的污点 输入: nMethod,去除0黑色污点,1去除白色污点 nMinArea,污点的最大面积,小于该污点的像素区域将被作为污点 输出: 去除成功返回true ******************************************************************/ bool CArdpsImg::AutoEliminateDirt(int nMethod, int nMinArea) { LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); if( !lpDIB) return false; LPBYTE lpBinImg = FindDIBBits(lpDIB); if( !lpBinImg ) { GlobalUnlock(m_hDib); return false; }bool bSuccess = true;
LONG nImgHei = GetHeight(); LONG nImgWid = GetWidth(); int nBitCnt = DIBBitCount(lpDIB); if( nBitCnt != 1 ) { GlobalUnlock(m_hDib); return false; } LONG nBinBytesPerLine = MYWIDTHBYTES(nImgWid * nBitCnt); //for gray image LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 ); LONG nGrayImgSize = nGrayBytesPerLine * nImgHei; BYTE *pbGrayImg = new BYTE[nGrayImgSize]; if( !pbGrayImg ) { GlobalUnlock(m_hDib); return false; } bSuccess = ConvertBinary2Gray(lpBinImg, nImgWid, nImgHei, pbGrayImg ); //SaveTo8bit_BMP(pbGrayImg, nImgWid, nImgHei, "d:\\testgray.bmp", 8); if( !bSuccess ) { delete []pbGrayImg; pbGrayImg = NULL; GlobalUnlock(m_hDib); return false; }Line *Li = new Line;
if( !Li ) { delete []pbGrayImg; pbGrayImg = NULL; GlobalUnlock(m_hDib); return false; }Li->StartY = 3;
Li->StartX = 3; Li->EndX = nImgWid - 3; Li->EndY = nImgHei - 3; Li->cp = NULL;BYTE bCur;
if( nMethod == 0 ) //黑色为背景 { bCur = 0; } else { bCur = 255; }ExtractComponent(Li, pbGrayImg, nGrayBytesPerLine, bCur );
AnalysisComponent(Li, pbGrayImg, nGrayBytesPerLine, nMinArea, 255- bCur); // SaveTo8bit_BMP(pbGrayImg, nImgWid, nImgHei, "d:\\testcom.bmp", 8); ThreshImage(pbGrayImg, lpBinImg, nImgWid, nImgHei, 128);if( pbGrayImg )
{ delete []pbGrayImg; pbGrayImg = NULL; }if( Li )
{ delete Li; Li = NULL; }GlobalUnlock(m_hDib);
return UpdateInternal();
}bool CArdpsImg::AutoEliminateDirt(int nMethod, CRect *pRect, int *pFlag, const int nNum)
{ if( !pRect || !pFlag ) return false;LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if( !lpDIB) return false; LPBYTE lpBinImg = FindDIBBits(lpDIB); if( !lpBinImg ) { GlobalUnlock(m_hDib); return false; }bool bSuccess = true;
LONG nImgHei = GetHeight(); LONG nImgWid = GetWidth(); int nBitCnt = DIBBitCount(lpDIB); if( nBitCnt != 1 ) { GlobalUnlock(m_hDib); return false; } LONG nBinBytesPerLine = MYWIDTHBYTES(nImgWid * nBitCnt); //for gray image LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 ); LONG nGrayImgSize = nGrayBytesPerLine * nImgHei; BYTE *pbGrayImg = new BYTE[nGrayImgSize]; if( !pbGrayImg ) { GlobalUnlock(m_hDib); return false; } bSuccess = ConvertBinary2Gray(lpBinImg, nImgWid, nImgHei, pbGrayImg ); if( !bSuccess ) { delete []pbGrayImg; pbGrayImg = NULL; GlobalUnlock(m_hDib); return false; } BYTE bCur; if( nMethod == 0 ) //黑色为背景 { bCur = 0; } else { bCur = 255; } CRect tmpRt; for( int i = 0; i < nNum; i++ ) { if (pFlag[i] == 1) { tmpRt.top = nImgHei - 1 - pRect[i].bottom; tmpRt.bottom = nImgHei - 1 - pRect[i].top; tmpRt.left = pRect[i].left; tmpRt.right = pRect[i].right; SetBinary(tmpRt, pbGrayImg, nGrayBytesPerLine, 255-bCur); } } ThreshImage(pbGrayImg, lpBinImg, nImgWid, nImgHei, 128);if( pbGrayImg )
{ delete []pbGrayImg; pbGrayImg = NULL; }GlobalUnlock(m_hDib);
return UpdateInternal();
} /****************************************************************** 功能:以原有图像中心为原点,给定的角度旋转图像 输入: iRotateAngle,指定旋转的度数,正值为向右旋转,反之向右旋转输出:
旋转成功返回true ******************************************************************/ bool CArdpsImg::RotateImage(int iRotateAngle /* = 0 */)\ {// 源图像的宽度和高度
LONG lWidth; LONG lHeight;// 旋转后图像的宽度和高度
LONG lNewWidth; LONG lNewHeight;// 图像每行的字节数
LONG lLineBytes;// 旋转后图像的宽度(lNewWidth',必须是4的倍数)
LONG lNewLineBytes;// 指向源图像的指针
LPBYTE lpDIBBits;// 指向源象素的指针
LPBYTE lpSrc;// 旋转后新DIB句柄
HDIB hDIB;// 指向旋转图像对应象素的指针
LPBYTE lpDst;// 指向旋转图像的指针
LPBYTE lpNewDIB; LPBYTE lpNewDIBBits; // 指向BITMAPINFO结构的指针(Win3.0) LPBITMAPINFOHEADER lpbmi;// 指向BITMAPCOREINFO结构的指针
LPBITMAPCOREHEADER lpbmc; // 旋转角度(弧度) float fRotateAngle;// 旋转角度的正弦和余弦
float fSina, fCosa;// 源图四个角的坐标(以图像中心为坐标系原点)
float fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;// 旋转后四个角的坐标(以图像中心为坐标系原点)
float fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;// 两个中间常量
float f1,f2; LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);// 找到源DIB图像象素起始位置
lpDIBBits = FindDIBBits(lpDIB);// 获取图像的"宽度"(4的倍数)
lWidth = DIBWidth(lpDIB);WORD dwBitCnt = DIBBitCount(lpDIB);
if (dwBitCnt != 8 && dwBitCnt != 24 && dwBitCnt != 1 ) { GlobalUnlock(m_hDib); return false; } // 获取图像的高度 lHeight = DIBHeight(lpDIB);LPBYTE pBin2Gray = NULL;
int lBin2GrayLineBytes = MYWIDTHBYTES(lWidth * 8);if( dwBitCnt == 1)
{ pBin2Gray = new BYTE[lBin2GrayLineBytes * lHeight]; if( !pBin2Gray ) { GlobalUnlock(m_hDib); return false; } memset(pBin2Gray, 0, lBin2GrayLineBytes * lHeight); ConvertBinary2Gray(lpDIBBits, lWidth, lHeight, pBin2Gray); lpDIBBits = pBin2Gray; } // 计算图像每行的字节数 lLineBytes = MYWIDTHBYTES(lWidth * dwBitCnt);
// 将旋转角度从度转换到弧度
fRotateAngle = (float) RADIAN(iRotateAngle);// 计算旋转角度的正弦
fSina = (float) sin((double)fRotateAngle);// 计算旋转角度的余弦
fCosa = (float) cos((double)fRotateAngle);// 计算原图的四个角的坐标(以图像中心为坐标系原点)
fSrcX1 = (float) (- (lWidth - 1) / 2); fSrcY1 = (float) ( (lHeight - 1) / 2); fSrcX2 = (float) ( (lWidth - 1) / 2); fSrcY2 = (float) ( (lHeight - 1) / 2); fSrcX3 = (float) (- (lWidth - 1) / 2); fSrcY3 = (float) (- (lHeight - 1) / 2); fSrcX4 = (float) ( (lWidth - 1) / 2); fSrcY4 = (float) (- (lHeight - 1) / 2);// 计算新图四个角的坐标(以图像中心为坐标系原点)
fDstX1 = fCosa * fSrcX1 + fSina * fSrcY1 - 0.5; fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1 - 0.5; fDstX2 = fCosa * fSrcX2 + fSina * fSrcY2 - 0.5; fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2 + 0.5; fDstX3 = fCosa * fSrcX3 + fSina * fSrcY3 + 0.5; fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3 - 0.5; fDstX4 = fCosa * fSrcX4 + fSina * fSrcY4 + 0.5; fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4 + 0.5;// 计算旋转后的图像实际宽度
lNewWidth = (LONG) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5); // 计算旋转后的图像高度 lNewHeight = (LONG) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) ) + 0.5);if( iRotateAngle == 90 || iRotateAngle == 270 )
{ lNewHeight = lWidth; lNewWidth = lHeight; } else if( iRotateAngle == 0 || iRotateAngle == 360 || iRotateAngle == 180 ) { lNewHeight = lHeight; lNewWidth = lWidth; } lNewLineBytes = MYWIDTHBYTES(lNewWidth * dwBitCnt); f1 = (float) (-0.5 * (lNewWidth - 1) * fCosa - 0.5 * (lNewHeight - 1) * fSina + 0.5 * (lWidth - 1)); f2 = (float) ( 0.5 * (lNewWidth - 1) * fSina - 0.5 * (lNewHeight - 1) * fCosa + 0.5 * (lHeight - 1));// 分配内存,以保存新DIB
hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));// 判断是否内存分配失败
if (hDIB == NULL) { GlobalUnlock(m_hDib); return false; }// 锁定内存
lpNewDIB = (LPBYTE)GlobalLock((HGLOBAL) hDIB);// 复制DIB信息头和调色板
memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + PaletteSize(lpDIB));// 找到新DIB象素起始位置
lpNewDIBBits = FindDIBBits(lpNewDIB);// 获取指针
lpbmi = (LPBITMAPINFOHEADER)lpNewDIB; lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;// 更新DIB中图像的高度和宽度
if (IS_WIN30_DIB(lpNewDIB)) { // 对于Windows 3.0 DIB lpbmi->biWidth = lNewWidth; lpbmi->biHeight = lNewHeight; } else { // 对于其它格式的DIB lpbmc->bcWidth = (unsigned short) lNewWidth; lpbmc->bcHeight = (unsigned short) lNewHeight; }LPBYTE pNewGray = NULL;
if( dwBitCnt == 1 ) { lNewLineBytes = MYWIDTHBYTES(lNewWidth * 8); lLineBytes = lBin2GrayLineBytes; pNewGray = new BYTE[lNewLineBytes * lNewHeight]; if( !pNewGray ) { GlobalUnlock(m_hDib); if( pBin2Gray ) delete []pBin2Gray; pBin2Gray = NULL; GlobalUnlock(hDIB); GlobalFree(hDIB); hDIB = NULL; return false; } lpNewDIBBits = pNewGray; } LONG i, j, m, i0, j0; for(i = 0, m = lNewLineBytes*(lNewHeight-1); i < lNewHeight; i++, m -= lNewLineBytes ) { lpDst = lpNewDIBBits + m; for(j = 0; j < lNewWidth; j++) { // 计算该象素在源DIB中的坐标 i0 = (LONG) (-((float) j) * fSina + ((float) i) * fCosa + f2 + 0.5); j0 = (LONG) ( ((float) j) * fCosa + ((float) i) * fSina + f1 + 0.5);// 判断是否在源图范围内
if( (j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 < lHeight)) { // 指向源DIB第i0行,第j0个象素的指针 if( dwBitCnt == 8 || dwBitCnt == 1 ) { lpSrc = lpDIBBits + lLineBytes *( lHeight - 1 -i0 )+ j0;// 复制象素
*lpDst ++= *lpSrc; } else if( dwBitCnt == 24 ) { lpSrc = lpDIBBits + lLineBytes *( lHeight - 1 -i0 )+ j0 * 3; *lpDst ++ = *lpSrc; lpSrc++; *lpDst ++ = *lpSrc; lpSrc++; *lpDst ++ = *lpSrc; }}
else { // 对于源图中没有的象素,直接赋值为255 if( dwBitCnt == 8 || dwBitCnt == 1) { * lpDst ++ = 255; } else if (dwBitCnt == 24) { *lpDst ++ = 255; *lpDst ++ = 255; *lpDst ++ = 255; } }}
} if( dwBitCnt == 1 ) { lpNewDIBBits = FindDIBBits(lpNewDIB); ThreshImage(pNewGray, lpNewDIBBits, lNewWidth,lNewHeight, 10); if( pNewGray ) delete []pNewGray; pNewGray = NULL;if( pBin2Gray )
delete []pBin2Gray; pBin2Gray = NULL;}
GlobalUnlock(m_hDib);
GlobalFree(m_hDib); m_hDib = hDIB; return UpdateInternal(); } /****************************************************************** 功能:以原有灰度图像中心为原点,自动检测角度并旋转图像 倾斜角度范围-10——+10度 输入: rtROI,给定的区域,用于检测文档的倾斜角度.输入区域为bottom = 0 或者right = 0,则设为图像区域 输出: 旋转成功返回true ******************************************************************/ bool CArdpsImg::AutoRotatelImage(RECT rtROI) { LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB); if( rtROI.bottom > lHeight || rtROI.right > lWidth ) { GlobalUnlock(m_hDib); return false; }if( rtROI.left < EDGE_STEP )
rtROI.left = EDGE_STEP; if( rtROI.right >= lWidth - EDGE_STEP ) rtROI.right = lWidth - EDGE_STEP - 1; if (rtROI.top < EDGE_STEP ) rtROI.top = EDGE_STEP; if( rtROI.bottom >= lHeight - EDGE_STEP ) rtROI.bottom = lHeight - 1 - EDGE_STEP;if( rtROI.bottom == 0 )
rtROI.bottom = lHeight-EDGE_STEP; if(rtROI.right == 0) rtROI.right = lWidth - EDGE_STEP; LPBYTE lpDIBBits = FindDIBBits(lpDIB);WORD dwBitCnt = DIBBitCount(lpDIB);
if( dwBitCnt != 8 ) { GlobalUnlock(m_hDib); return false; } LONG lLineBytes = MYWIDTHBYTES(lWidth * dwBitCnt); BYTE * pbOutImage = new BYTE[lLineBytes * lHeight]; if( !pbOutImage ) { GlobalUnlock(m_hDib); return false; } memset(pbOutImage, 0, lLineBytes * lHeight* sizeof(BYTE)); BYTE *pbTmp = new BYTE[lLineBytes * lHeight]; if( !pbTmp ) { GlobalUnlock(m_hDib); delete []pbOutImage; pbOutImage = NULL; } memset(pbTmp, 0, lLineBytes * lHeight* sizeof(BYTE));bool bSuccess = FindTopEdge(pbOutImage, lpDIBBits, rtROI, lLineBytes);
//SaveTo8bit_BMP(lpDIBBits, lWidth, lHeight, "edgegray.bmp", 8); //SaveTo8bit_BMP(pbOutImage, lWidth, lHeight, "edge0.bmp", 8); DeleteVtlSmallLine(pbOutImage, pbTmp, lLineBytes, lHeight, 5); //SaveTo8bit_BMP(pbOutImage, lWidth, lHeight, "edge1.bmp", 8); double dK; if( bSuccess ) { dK = DetectSkewAngle(pbOutImage, rtROI, lLineBytes); bSuccess = RotateImage(dK); } if( pbOutImage ) { delete []pbOutImage; pbOutImage = NULL; }if( pbTmp )
{ delete []pbTmp; pbTmp = NULL; }GlobalUnlock(m_hDib);
if( bSuccess ) return UpdateInternal(); else return bSuccess; } /****************************************************************** 功能:自动去除灰度图像的黑白边 输入:输出:
去除成功返回true ******************************************************************/ bool CArdpsImg::CutFrame() { BYTE * pbOut = NULL; bool bSuccess = false; LPBITMAPINFOHEADER lpbmi = NULL; LPBITMAPCOREHEADER lpbmc = NULL; LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB);LPBYTE lpDIBBits = FindDIBBits(lpDIB);
WORD dwBitCnt = DIBBitCount(lpDIB);
if( dwBitCnt != 8 ) { goto CleanUp; } RECT rect; rect = SetRectValue(0, 0, 0, 0); LONG lLineBytes = MYWIDTHBYTES(lWidth << 3); LONG lImgBytes = lLineBytes * lHeight; pbOut = new BYTE[lImgBytes]; if( !pbOut ) { goto CleanUp; } memset(pbOut, 0, lImgBytes * sizeof(BYTE));rect = SetRectValue(4, lWidth - 4, 4, lHeight - 4);
if (FindEdgeImage(pbOut, lpDIBBits, rect, lWidth) < 0) { goto CleanUp; }rect = GetEdgeImageBoundary(pbOut, lWidth, lHeight);
RECT rtPhy; rtPhy = rect; rtPhy.bottom = lHeight - 1 - rect.top; rtPhy.top = lHeight - 1 - rect.bottom; HDIB hDIB = CropDIB(m_hDib, &rtPhy); if( hDIB == NULL ) goto CleanUp;bSuccess = true;
CleanUp:
if( pbOut )
{ delete []pbOut; pbOut = NULL; }GlobalUnlock(m_hDib);
GlobalFree(m_hDib); m_hDib = hDIB; if( bSuccess ) return UpdateInternal(); else return bSuccess; } /****************************************************************** 功能:将图像拆页为两幅图像 输入: pt1,pt2:给定的拆分的线的任意两点坐标 pNewArd:返回CArdpsImg对象,拆分后的下、右半幅图像句柄存于该对象中 输出: 拆分成功返回true ******************************************************************/ bool CArdpsImg::SplitImage(POINT pt1, POINT pt2, CArdpsImg *pNewArd) { bool bSuccess = false; if( pNewArd == NULL ) return bSuccess;LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB); int nx, ny; nx = abs(pt1.x - pt2.x) ; ny = abs(pt1.y - pt2.y) >lHeight - 1 ? lHeight - 1 : abs(pt1.y - pt2.y) ; RECT rtROI, rtROI2; if( nx < ny ) { nx = (pt1.x + pt2.x + 0.5)/2 > lWidth - 1 ? lWidth - 1 : (pt1.x + pt2.x + 0.5)/2; //垂直分割 rtROI = SetRectValue(0, nx -1, 0, lHeight - 1); rtROI2 = SetRectValue(nx, lWidth -1, 0, lHeight - 1); } else { ny = (pt1.y + pt2.y + 0.5) / 2 > lHeight - 1 ? lHeight - 1 : (pt1.y + pt2.y + 0.5) / 2 ; rtROI = SetRectValue(0, lWidth - 1, 0, ny - 1); rtROI2 = SetRectValue(0, lWidth - 1, ny, lHeight - 1); }HDIB hDib1, hDib2;
hDib1 = CropDIB(m_hDib, &rtROI );
hDib2 = CropDIB(m_hDib, &rtROI2); GlobalUnlock(m_hDib); GlobalFree(m_hDib);m_hDib = hDib1;
pNewArd->m_hDib = hDib2; return true;}
/****************************************************************** 功能:将两幅图像合并为一幅图像 输入: pSrcArd:输入的CArdpsImg对象,图像的句柄存于该对象中 nMethod:0:上下合并,Src位于合并后的下半幅;1:上下合并,Src位于合并后的上半幅 2:左右合并,Src位于合并后的右半幅;3:左右合并,Src位于合并后的左半幅 输出: 拆分成功返回true ******************************************************************/bool CArdpsImg::MergeImage(CArdpsImg *pSrcArd, int nMethod /* = 0 */)
{ bool bSuccess = false; if( pSrcArd == NULL ) return bSuccess;//当前图像
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); LONG lWidth = DIBWidth(lpDIB); LONG lHeight = DIBHeight(lpDIB); WORD bitCnt = DIBBitCount(lpDIB); LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt); LPBYTE lpDIBBits = FindDIBBits(lpDIB);//欲合并的图像
LPBYTE lpSrcDIB = (LPBYTE)GlobalLock(pSrcArd->m_hDib); LONG lSrcWidth = DIBWidth(lpSrcDIB); LONG lSrcHeight = DIBHeight(lpSrcDIB); WORD bitSrcCnt = DIBBitCount(lpSrcDIB); LONG lSrcBytePerLine = MYWIDTHBYTES(lSrcWidth * bitSrcCnt); if( bitCnt != bitSrcCnt || bitCnt < 8 ) goto CleanUp;LPBYTE lpSrcDIBBits = FindDIBBits(lpSrcDIB);
LONG lDstWidth, lDstHeight, lDstBytesPerLine, i, j, k;
HDIB hDIB = NULL; LPBYTE lpDstDIB, lpDstDIBBits; lpDstDIB = lpDstDIBBits = NULL;switch (nMethod)
{ case 0: case 1: lDstHeight = lSrcHeight + lHeight; lDstWidth = max(lWidth, lSrcWidth); break; case 2: case 3: default: lDstHeight = max(lSrcHeight, lHeight); lDstWidth = lWidth + lSrcWidth; } lDstBytesPerLine = MYWIDTHBYTES(lDstWidth*bitCnt);// 分配内存,以保存新DIB
hDIB = (HDIB) ::GlobalAlloc(GHND, lDstBytesPerLine * lDstHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); if( hDIB == NULL ) goto CleanUp;lpDstDIB = (LPBYTE)GlobalLock(hDIB);
// 获取指针 LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpDstDIB; LPBITMAPCOREHEADER lpbmc = (LPBITMAPCOREHEADER)lpDstDIB;// 复制DIB信息头和调色板
memcpy(lpDstDIB, lpDIB, *(LPDWORD)lpDIB + PaletteSize(lpDIB));lpDstDIBBits = lpDstDIB + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB);
memset(lpDstDIBBits, 255, lDstBytesPerLine * lDstHeight * sizeof(BYTE)); switch (nMethod) { case 0: //上下结构,Src位于图像的下半部分for( i = 0, j = 0, k = 0; i < lSrcHeight; i++, j += lDstBytesPerLine, k += lSrcBytePerLine )
{ memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine); } for( i = lSrcHeight, j = i * lDstBytesPerLine, k = 0; i < lDstHeight; i++, j += lDstBytesPerLine, k += lBytePerLine ) { memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine ); }break;
case 1: //上下结构,当前图像位于合并后图像的下半部分for( i = 0, j = 0, k = 0; i < lHeight; i++, j += lDstBytesPerLine, k += lBytePerLine )
{ memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine); } for( i = lHeight, j = i * lDstBytesPerLine, k = 0; i < lDstHeight; i++, j += lDstBytesPerLine, k += lSrcBytePerLine ) { memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine ); } break; case 2: //左右结构,Src图像位于合并后图像的右半部分 for( i = 0, j = 0, k = 0; i < lHeight; i++, j += lDstBytesPerLine, k += lBytePerLine) { memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine); } for( i = 0, j = lBytePerLine, k = 0; i < lSrcHeight; i++, j += lDstBytesPerLine, k += lSrcBytePerLine ) { memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine); } break; case 3: //左右结构,当前图像位于合并后图像的右半部分 default: for( i = lSrcHeight - 1, j = i * lDstBytesPerLine, k = i * lSrcBytePerLine; i >= 0; i--, j -= lDstBytesPerLine, k -= lSrcBytePerLine) { memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine); } for( i = lHeight - 1, j = i * lDstBytesPerLine + lSrcBytePerLine, k = i * lBytePerLine; i >= 0; i--, j -= lDstBytesPerLine, k -= lBytePerLine ) { memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine); } break;}
// 更新DIB中图像的高度和宽度
if (IS_WIN30_DIB(lpDIB)) { // 对于Windows 3.0 DIB lpbmi->biWidth = lDstWidth; lpbmi->biHeight = lDstHeight; } else { // 对于其它格式的DIB lpbmc->bcWidth = (unsigned short) lDstWidth; lpbmc->bcHeight = (unsigned short) lDstHeight; } bSuccess = true; CleanUp:GlobalUnlock(m_hDib);
GlobalFree(m_hDib); GlobalUnlock(pSrcArd->m_hDib); if( bSuccess && hDIB != NULL ) m_hDib = hDIB; if( bSuccess ) return UpdateInternal(); else return bSuccess; }/******************************************************************
功能:将两幅图像合并为一幅图像 输入: pSrcArd:输入的CArdpsImg对象,图像的句柄存于该对象中 nPos1: 当前图像的合并坐标; nPos2 输入的CArdpsImg对象,合并图像的坐标 nMethod:0:上下合并,取当前图像的下部,pSrcArd图像的上部 1:左右合并,取当前图像的右部,pSrcArd图像的下部 输出: 当前图像为合并后的图像,合并成功返回true ******************************************************************/bool CArdpsImg::MergeImage(CArdpsImg *pSrcArd, int nPos1, int nPos2, int nMethod /* = 0 */)
{ bool bSuccess = false; if( pSrcArd == NULL ) return bSuccess;//当前图像
LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); LONG lWidth = DIBWidth(lpDIB); LONG lHeight = DIBHeight(lpDIB); WORD bitCnt = DIBBitCount(lpDIB); LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt); LPBYTE lpDIBBits = FindDIBBits(lpDIB);//欲合并的图像
LPBYTE lpSrcDIB = (LPBYTE)GlobalLock(pSrcArd->m_hDib); LONG lSrcWidth = DIBWidth(lpSrcDIB); LONG lSrcHeight = DIBHeight(lpSrcDIB); WORD bitSrcCnt = DIBBitCount(lpSrcDIB); LONG lSrcBytePerLine = MYWIDTHBYTES(lSrcWidth * bitSrcCnt); if( bitCnt != bitSrcCnt || bitCnt < 8 ) goto CleanUp;LPBYTE lpSrcDIBBits = FindDIBBits(lpSrcDIB);
LONG lDstWidth, lDstHeight, lDstBytesPerLine, i, j, k;
HDIB hDIB = NULL; LPBYTE lpDstDIB, lpDstDIBBits; lpDstDIB = lpDstDIBBits = NULL;nPos1 -= 1;
nPos2 -= 1; switch (nMethod) { case 0:if( nPos1 >= lHeight )
nPos1 = lHeight - 1; if( nPos1 < 0 ) nPos1 = 0; if( nPos2 >= lSrcHeight ) nPos2 = lSrcHeight - 1; if( nPos2 < 0 ) nPos2 = 0; lDstHeight = nPos2 + lHeight - nPos1; lDstWidth = max(lWidth, lSrcWidth); break; case 1: if (nPos1 >= lWidth ) nPos1 = lWidth - 1; if( nPos1 < 0 ) nPos1 = 0;if( nPos2 >= lSrcWidth )
nPos2 = lSrcWidth - 1; if( nPos2 < 0 ) nPos2 = 0;lDstHeight = max(lSrcHeight, lHeight);
lDstWidth = lWidth - nPos1 + nPos2; } lDstBytesPerLine = MYWIDTHBYTES(lDstWidth*bitCnt);// 分配内存,以保存新DIB
hDIB = (HDIB) ::GlobalAlloc(GHND, lDstBytesPerLine * lDstHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); if( hDIB == NULL ) goto CleanUp;lpDstDIB = (LPBYTE)GlobalLock(hDIB);
// 获取指针 LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpDstDIB; LPBITMAPCOREHEADER lpbmc = (LPBITMAPCOREHEADER)lpDstDIB;// 复制DIB信息头和调色板
memcpy(lpDstDIB, lpDIB, *(LPDWORD)lpDIB + PaletteSize(lpDIB));lpDstDIBBits = lpDstDIB + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB);
memset(lpDstDIBBits, 255, lDstBytesPerLine * lDstHeight * sizeof(BYTE));int nLength = 0;
switch (nMethod) { case 0: //上下结构,当前图像位于合并图像的下半部分for( i = 0, j = 0, k = 0; i < lHeight - nPos1; i++, j += lDstBytesPerLine, k += lBytePerLine )
{ memcpy(lpDstDIBBits + j, lpDIBBits + k, lBytePerLine); }for( i = lSrcHeight - nPos2 , k = i * lSrcBytePerLine; i < lSrcHeight; i++, j += lDstBytesPerLine, k += lSrcBytePerLine )
{ memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, lSrcBytePerLine ); }break;
case 1: //左右结构,当前图像位于合并后图像的右半部分
nLength = nPos2 * bitCnt / 8; for( i = 0, k = 0, j = 0; i < lSrcHeight; i++, k += lSrcBytePerLine, j += lDstBytesPerLine ) { memcpy(lpDstDIBBits + j, lpSrcDIBBits + k, nLength); } nLength = (lWidth - nPos1) * bitCnt / 8; for( i = 0, k = nPos1 * bitCnt / 8, j = nPos2 * bitCnt / 8; i < lHeight; i++, k+= lBytePerLine, j += lDstBytesPerLine ) { memcpy(lpDstDIBBits + j, lpDIBBits + k, nLength); } break; }// 更新DIB中图像的高度和宽度
if (IS_WIN30_DIB(lpDIB)) { // 对于Windows 3.0 DIB lpbmi->biWidth = lDstWidth; lpbmi->biHeight = lDstHeight; } else { // 对于其它格式的DIB lpbmc->bcWidth = (unsigned short) lDstWidth; lpbmc->bcHeight = (unsigned short) lDstHeight; } bSuccess = true; CleanUp:GlobalUnlock(m_hDib);
GlobalFree(m_hDib); GlobalUnlock(pSrcArd->m_hDib); if( bSuccess && hDIB != NULL ) m_hDib = hDIB; if( bSuccess ) return UpdateInternal(); else return bSuccess; } /** * Changes the brightness and the contrast of the image. Apply a look up table to the image. * \ * \param brightness: can be from -255 to 255, if brightness is negative, the image becomes dark. * \param contrast: can be from -100 to 100, the neutral value is 0. * \return true if everything is ok */ bool CArdpsImg::AjustLightAndContrast(int brightness, int contrast) { if (!m_hDib) return false; float c=(100 + contrast)/100.0f; brightness+=128; long i; BYTE cTable[256]; //<nipper> for ( i=0;i<256;i++) { cTable[i] = (BYTE)max(0,min(255,(int)((i-128)*c + brightness + 0.5f))); }LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); if( lpDIB == NULL ) return false;
LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB); WORD bitCnt = DIBBitCount(lpDIB); LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt); LPBYTE lpDIBBits = FindDIBBits(lpDIB); RGBQUAD *pRgb =(RGBQUAD *)( lpDIB + 40); if (bitCnt == 8) { for( i = 0; i < 256; i++) { pRgb[i].rgbBlue = pRgb[i].rgbRed = pRgb[i].rgbGreen = cTable[i]; } } else if( bitCnt == 24) { for( i = 0; i < lBytePerLine * lHeight; i++) { *lpDIBBits++ = cTable[*lpDIBBits]; } } else { GlobalUnlock(m_hDib); return false; }GlobalUnlock(m_hDib);
return UpdateInternal(); } /****************************************************************** 功能:自动分析边框,并进行调整,不改变图像的大小 输入:nMethod:0:从水平,垂直两个方向上进行调整。
1:水平调整 2:垂直调整 输出: 调整后的图像,成功返回true ******************************************************************/bool CArdpsImg::AdjustBinPos(int nMethod /* = 0 */)
{ LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); if( lpDIB == NULL ) return false;LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB); WORD bitCnt = DIBBitCount(lpDIB); LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt); LPBYTE lpDIBBits = FindDIBBits(lpDIB); if( bitCnt != 1 ) { GlobalUnlock(m_hDib); return false; }//for gray image
LONG nGrayBytesPerLine = MYWIDTHBYTES( lWidth << 3 ); LONG nGrayImgSize = nGrayBytesPerLine * lHeight; BYTE *pbGrayImg = new BYTE[nGrayImgSize]; if( !pbGrayImg ) { GlobalUnlock(m_hDib); return false; } bool bSuccess = ConvertBinary2Gray(lpDIBBits, lWidth, lHeight, pbGrayImg ); if( !bSuccess ) { GlobalUnlock(m_hDib); delete []pbGrayImg; pbGrayImg = NULL; return false; } RECT rtImg = GetBinImageBoundary(pbGrayImg, lWidth, lHeight); RECT rtNew; rtNew.left = (rtImg.left + lWidth - rtImg.right )/2; rtNew.right = lWidth - rtNew.left -1; rtNew.top = (rtImg.top + lHeight - rtImg.bottom)/2; rtNew.bottom = lHeight - rtNew.top - 1; MoveBin(pbGrayImg, lWidth, lHeight, rtImg, rtNew, nMethod ); bSuccess = ThreshImage(pbGrayImg, lpDIBBits, lWidth, lHeight, 10);if( pbGrayImg )
delete []pbGrayImg; pbGrayImg = NULL;GlobalUnlock(m_hDib);
return UpdateInternal();
} /****************************************************************** 功能:彩色图像色阶调整 输入:输出:
调整后的图像,成功返回true ******************************************************************/ bool CArdpsImg::ColorEqual() { LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); if( lpDIB == NULL ) return false;LONG lWidth = DIBWidth(lpDIB);
LONG lHeight = DIBHeight(lpDIB); WORD bitCnt = DIBBitCount(lpDIB); LONG lBytePerLine = MYWIDTHBYTES(lWidth * bitCnt); LPBYTE lpDIBBits = FindDIBBits(lpDIB);if( bitCnt != 24 )
{ GlobalUnlock(m_hDib); return false; } int nHist[256]; long long nCulHist[256]; long long nConver[256];memset(nHist, 0, 256 * sizeof(int));
memset(nCulHist, 0, 256 * sizeof( long long )); memset(nConver, 0, 256 * sizeof(long long ));long i, j, m, newValue;
LPBYTE pSrc = NULL; for( i = 0, m = 0; i < lHeight; i++, m += lBytePerLine ) { pSrc = lpDIBBits + m; for( j = 0; j < lWidth; j++) { newValue = (*pSrc) * uiBWeight + uiGWeight * (*(pSrc + 1)) + uiRWeight * (*(pSrc + 2)); newValue /= 1000; nHist[newValue]++; pSrc += 3; } } long long nTotal = lHeight * lWidth; nCulHist[0] = nHist[0]; nConver[0] = nHist[0] * 255 / nTotal; for( i = 1; i < 256; i++ ) { nCulHist[i] = nCulHist[i - 1] + nHist[i]; nConver[i] = nCulHist[i] * 255 / nTotal; }for( i = 0, m = 0; i < lHeight; i++, m += lBytePerLine )
{ pSrc = lpDIBBits + m; for( j = 0; j < lWidth; j++) { *pSrc = nConver[*pSrc]; pSrc++; *pSrc = nConver[*pSrc]; pSrc++; *pSrc = nConver[*pSrc]; pSrc++; } }GlobalUnlock(m_hDib);
return UpdateInternal();
}
bool CArdpsImg::Zoom(double fRatioX, double fRatioY)
{ int nWidth = (int)(fRatioX * (double)GetWidth()); int nHeight = (int)(fRatioY * (double)GetHeight());HDIB hNewDib = ChangeDIBSize(m_hDib, nWidth, nHeight);
if (! hNewDib) return false;// set to m_hDib
Destroy(); m_hDib = hNewDib;// return
return UpdateInternal(); }//连通域提取
void CArdpsImg::ExtractComponent(Line * Li, BYTE *pbBinary, UINT grayBytesPerLine, BYTE bCur ) //连通域提取 { if( Li == NULL || pbBinary == NULL ) return; int * stack = NULL; int * InStack[10]; int top, topin; top = topin = 0;CPoint temp;
component *ctail =NULL; component *chead =new component;InStack[topin] = new int[COMP_NUM];
if( InStack[topin] == NULL ) return;stack = InStack[topin];
char **flag=new char*[Li->EndY-Li->StartY+1];
if( *flag == NULL ) { delete []InStack[topin]; InStack[topin] = NULL; return; }int i, j, k;
for(i = 0; i <= Li->EndY - Li->StartY; i++) //寻找连通体
{ flag[i]=new char[Li->EndX - Li->StartX + 1]; for(j = 0; j <= Li->EndX - Li->StartX; j++) { flag[i][j]=0; } }for(j = Li->StartX; j <= Li->EndX; j++) //寻找连通体
{ for( i = Li->StartY, k = Li->StartY * grayBytesPerLine; i <= Li->EndY; i++, k += grayBytesPerLine) { if(flag[i-Li->StartY][j-Li->StartX] == 0 && pbBinary[k + j] == bCur ) { stack[top++]=i; stack[top++]=j;flag[i - Li->StartY][j - Li->StartX] = 1;
if(ctail!=NULL) { component *cp = new component; ctail->cnext = cp; ctail = cp; } else { ctail = chead; } ctail->bound =CRect(j,i,j,i); ctail->count =1;while(top != 0)
{ temp.x = stack[--top]; temp.y = stack[--top]; if(top == 0 && topin != 0) { stack = InStack[topin-1]; delete []InStack[topin--]; top = COMP_NUM; } if(temp.x - 1 >= Li->StartX) add(temp.x-1, temp.y, flag, stack, InStack, top, topin, Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur ); if(temp.x+1 <= Li->EndX) add(temp.x+1, temp.y, flag, stack, InStack, top, topin, Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur); if(temp.y-1 >= Li->StartY) add(temp.x, temp.y-1, flag, stack, InStack, top, topin, Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur); if(temp.y+1 <= Li->EndY) add(temp.x, temp.y+1, flag, stack, InStack, top, topin, Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur); if((temp.x-1 >= Li->StartX) && (temp.y - 1 >= Li->StartY)) add(temp.x-1, temp.y-1, flag, stack, InStack, top, topin, Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur); if((temp.x+1 <= Li->EndX) && (temp.y-1 >= Li->StartY)) add(temp.x+1, temp.y-1, flag, stack, InStack, top, topin, Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur); if((temp.x-1 >= Li->StartX) && (temp.y+1 <= Li->EndY)) add(temp.x-1, temp.y+1, flag, stack, InStack, top, topin, Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur); if((temp.x+1 <= Li->EndX) && (temp.y+1 <= Li->EndY)) add(temp.x+1, temp.y+1, flag, stack, InStack, top, topin, Li->StartX, Li->StartY, ctail, pbBinary, grayBytesPerLine, bCur); } } } } //end for Li->cp = chead;delete []stack;
for(i = 0; i <= Li->EndY-Li->StartY; i++)
delete []flag[i];delete []flag;
}
void CArdpsImg::add(int a,int b,char **flag,int *&stack,int **InStack, int &top,int &topin,int c,int d,component *ctail, BYTE *pMotion, UINT grayBytesPerLine, BYTE bCur ) { if((flag[b-d][a-c] == 0 ) && pMotion[b * grayBytesPerLine + a] == bCur ) { flag[b-d][a-c] = 1;if(top == COMP_NUM)
{ if(topin == 9) { return; } InStack[++topin]=new int[COMP_NUM]; stack=InStack[topin]; top=0; } stack[top++]=b; stack[top++]=a; ctail->count++;if(ctail->bound.bottom < b) //连通体边界
ctail->bound.bottom = b; if(ctail->bound.top > b) ctail->bound.top = b; if(ctail->bound.left > a) ctail->bound.left = a; if(ctail->bound.right < a) ctail->bound.right = a; } }void CArdpsImg::AnalysisComponent( Line * Li, BYTE *pbBinary, UINT unBinaryBytesPerLine, UINT minArea, const BYTE bValue)
{ if( Li == NULL || pbBinary == NULL ) return; component *cp1= Li->cp; component *cp2; int area;//, nCnt = 0; while( cp1 != NULL ) { area = cp1->bound.Height() * cp1->bound.Width(); if( area < minArea && area > 0 ) { SetBinary(cp1->bound, pbBinary, unBinaryBytesPerLine, bValue); }cp2 = cp1;
cp1 = cp1->cnext;delete cp2;
}Li->cp = NULL;
}
CRect* CArdpsImg::GetDirtPos(int nMethod, int *nCnt)
{ *nCnt = 0;LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib);
if( !lpDIB) return m_dirRect;LPBYTE lpBinImg = FindDIBBits(lpDIB);
if( !lpBinImg ) { GlobalUnlock(m_hDib); return m_dirRect; }bool bSuccess = true;
LONG nImgHei = GetHeight(); LONG nImgWid = GetWidth(); int nBitCnt = DIBBitCount(lpDIB); if( nBitCnt != 1 ) { GlobalUnlock(m_hDib); return m_dirRect; } LONG nBinBytesPerLine = MYWIDTHBYTES(nImgWid * nBitCnt); //for gray image LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 ); LONG nGrayImgSize = nGrayBytesPerLine * nImgHei; BYTE *pbGrayImg = new BYTE[nGrayImgSize]; if( !pbGrayImg ) { GlobalUnlock(m_hDib); return m_dirRect; } bSuccess = ConvertBinary2Gray(lpBinImg, nImgWid, nImgHei, pbGrayImg ); //SaveTo8bit_BMP(pbGrayImg, nImgWid, nImgHei, "d:\\testgray.bmp", 8); if( !bSuccess ) { delete []pbGrayImg; pbGrayImg = NULL; GlobalUnlock(m_hDib); return m_dirRect; }Line *Li = new Line;
if( !Li ) { delete []pbGrayImg; pbGrayImg = NULL; GlobalUnlock(m_hDib); return m_dirRect; }Li->StartY = 3;
Li->StartX = 3; Li->EndX = nImgWid - 3; Li->EndY = nImgHei - 3; Li->cp = NULL;BYTE bCur;
if( nMethod == 0 ) //黑色为背景 { bCur = 0; } else { bCur = 255; }ExtractComponent(Li, pbGrayImg, nGrayBytesPerLine, bCur );
AnalysisDirtPos(Li, m_DirtSize, m_minDirtSize, nImgHei, nCnt);if( pbGrayImg )
{ delete []pbGrayImg; pbGrayImg = NULL; }if( Li )
{ delete Li; Li = NULL; }GlobalUnlock(m_hDib);
return m_dirRect; }bool CArdpsImg::AnalysisDirtPos(Line *Li, CSize maxSize, CSize minSize, int nHeight, int *nCnt)
{ if( Li == NULL || nCnt == NULL ) return false; component *cp1= Li->cp; component *cp2; int area;//, nCnt = 0; int minArea = minSize.cx * minSize.cy; int maxArea = maxSize.cx * maxSize.cy; *nCnt = 0; while(cp1 != NULL ) { cp1 = cp1->cnext; (*nCnt)++; } if( m_dirRect ) { delete []m_dirRect; m_dirRect = NULL; } m_dirRect = new CRect[(*nCnt)]; if( m_dirRect == NULL ) return false;cp1= Li->cp;
*nCnt = 0; while( cp1 != NULL ) { area = cp1->bound.Height() * cp1->bound.Width(); if( area <= maxArea && area >= minArea ) { m_dirRect[*nCnt].top = nHeight - 1 - cp1->bound.bottom; m_dirRect[*nCnt].bottom = nHeight - 1 - cp1->bound.top; m_dirRect[*nCnt].left = cp1->bound.left; m_dirRect[*nCnt].right = cp1->bound.right; (*nCnt)++; }cp2 = cp1;
cp1 = cp1->cnext;delete cp2;
}Li->cp = NULL;
return true; }void CArdpsImg::SetBinary(CRect rect, BYTE *pbImg, UINT unBinaryBytesPerLine, const BYTE bValue)
{ if( pbImg == NULL ) return;LONG i, j, m;
for( i = rect.top, m = rect.top * unBinaryBytesPerLine; i <= rect.bottom; i++, m += unBinaryBytesPerLine ) { for( j = rect.left; j <= rect.right; j++ ) { *(pbImg + m + j) = bValue; } } }bool CArdpsImg::ConvertBinary2Gray(const unsigned char * pbBinary, const int nWidth, const int nHeight, unsigned char *pbGray)
{ if( pbBinary == NULL || pbGray == NULL || nWidth < 1 || nHeight < 1) return false;LONG nBinaryBytesPerLine = MYWIDTHBYTES(nWidth);
LONG nGrayBytesPerLine = MYWIDTHBYTES(nWidth << 3); LONG i, j, k, m; const unsigned char * pbIn = pbBinary; unsigned char * pbOut = pbGray; memset( pbGray, 0, nHeight * nGrayBytesPerLine * sizeof( unsigned char)); BYTE btmp = 0; for( i = 0, k = 0, m = 0; i < nHeight; i++, k += nGrayBytesPerLine, m += nBinaryBytesPerLine ) { pbIn = pbBinary + m; pbOut = pbGray + k; for( j = 0; j < (nWidth + 7)/8; j++, pbIn++) { btmp = *pbIn; btmp = btmp & 128 ; if( btmp == 128) *pbOut = 255; pbOut ++;btmp = *pbIn;
btmp = btmp & 64 ; if( btmp == 64) *pbOut = 255; pbOut ++;btmp = *pbIn;
btmp = btmp & 32 ; if( btmp == 32) *pbOut = 255; pbOut ++; btmp = *pbIn; btmp = btmp & 16 ; if( btmp == 16) *pbOut = 255; pbOut ++;btmp = *pbIn;
btmp = btmp & 8 ; if( btmp == 8) *pbOut = 255; pbOut ++;btmp = *pbIn;
btmp = btmp & 4 ; if( btmp == 4) *pbOut = 255; pbOut ++;btmp = *pbIn;
btmp = btmp & 2 ; if( btmp == 2) *pbOut = 255; pbOut ++;btmp = *pbIn;
btmp = btmp & 1; if( btmp == 1) *pbOut = 255; pbOut ++; } } return true; }
bool CArdpsImg::FindTopEdge(BYTE *pbOutImage, BYTE *image, RECT rtROI, int nWidth)
{ if( pbOutImage == NULL || image == NULL ) return false;BYTE *pbIn1, *pbIn2;
pbIn2 = pbIn1 = NULL; int i, j; int gd, n = 0, k = 0; int d;gd = n = 0;
pbIn1 = image + (rtROI.top + EDGE_STEP) * nWidth + rtROI.left; for (i = rtROI.top + EDGE_STEP; i < rtROI.bottom; i++, pbIn1 += nWidth) { pbIn2 = pbIn1; for (j = rtROI.left; j < rtROI.right; j++, pbIn2++) { d = pbIn2[-EDGE_STEP * nWidth] - pbIn2[0]; if (d > 20) { gd += d; n++; } } } if (n > 0) { gd = gd / n; }pbIn1 = image + rtROI.top * nWidth + rtROI.left;
for (i = rtROI.top; i < rtROI.bottom; i++, pbIn1 += nWidth) { pbIn2 = pbIn1; for (j = rtROI.left; j < rtROI.right; j++, pbIn2++) { n = (int)(pbIn2 - image); pbOutImage[n] = 0; if (j > EDGE_STEP) { d = pbIn2[nWidth - EDGE_STEP] - pbIn2[0]; if (d > gd) { pbOutImage[n] = 255; } } } } for (i = rtROI.top; i < rtROI.bottom; i++) { for (j = rtROI.right; j > rtROI.left; j--) { if (pbOutImage[i * nWidth + j] <= pbOutImage[i * nWidth + j - 1]) { pbOutImage[i * nWidth + j] = 0; } } }return true;
}double CArdpsImg::DetectSkewAngle(BYTE *pbImage, RECT rtROI, int nWidth)
{ double dK = 0.0; int i; int nValeSum, nValeMax, angle; int *pnRamBuff = NULL; pnRamBuff = new int[nWidth * 2]; if (pnRamBuff == NULL) { return 0.0; }angle = nValeMax = 0;
for (i = -10; i <= 10; i ++) { nValeSum = CompVPrjValeSum(pnRamBuff, pbImage, nWidth, rtROI.bottom, i); if(nValeSum>nValeMax) { nValeMax = nValeSum; angle = i; } } dK = angle;// * 3.14159265 / 180;if( pnRamBuff)
{ delete []pnRamBuff; pnRamBuff = NULL; }return dK;
} // compute all vale sum int CArdpsImg::CompVPrjValeSum(int *pnRamBuff, const BYTE *pInImg, int nImgWidth, int nImgHeight, int nRotAngle) { if( pnRamBuff == NULL || pInImg == NULL ) return 0; int nValeSum = 0; int i, j; int *nVprj = pnRamBuff, *nPlot = NULL; int nPrjLen; int nPrjOffset; int nPx; int nSin, nCos; const BYTE *pb = NULL;if((nRotAngle >= 0) && (nRotAngle <= 90))
{ nSin = g_nSin[nRotAngle]; nCos = g_nCos[nRotAngle]; } else if ((nRotAngle < 0)&&(nRotAngle > -90)) { nSin = -g_nSin[-nRotAngle]; nCos = g_nCos[-nRotAngle]; }// compute max project length
i = nSin > 0 ? nSin : -nSin; nPrjLen = nImgWidth*nCos+nImgHeight*i+32768; nPrjLen = nPrjLen>>16; if (nPrjLen>nImgWidth) { nPrjLen = nImgWidth; } if (nSin<0) { nPrjOffset = -nImgHeight*nSin+32768; nPrjOffset = nPrjOffset>>16; } else { nPrjOffset = 0; }memset(nVprj, 0, nPrjLen * 2 * sizeof(int));
nPlot = nVprj + nPrjLen;pb = pInImg;
for (i = 0; i < nImgHeight; i++) { for (j = 0; j < nImgWidth; j++, pb++) { if (*pb < 8) continue; nPx = j * nCos + i * nSin + 32768; nPx = (nPx >> 16) + nPrjOffset; if((nPx < nPrjLen) && (nPx>=0)) { nVprj[nPx] += *pb; } } }SmoothingArray(nPlot, 1, nVprj, 0, nPrjLen);
nValeSum = 0; for(i = 0; i < nPrjLen; i++) { if (nPlot[i]==0) { nValeSum++; } }return nValeSum;
}//--------------------------------------------------------------------
// NAME: SmoothingArray // PARAMS: int *pIn, input array // int *pOut, output array // int nR, smooth radius // int nStart, int nEnd, the begin and end of smoothing // RETURN: NULL // FUNCTION: Smoothing one-dimentional array //--------------------------------------------------------------------- void CArdpsImg::SmoothingArray(int *pOut, int nR, const int *pIn, int nStart, int nEnd) { if( pIn == NULL || pOut == NULL ) return;int i, nSum, nCount;
int beg, end;nSum = 0;
// the len is less than nR
if (nEnd - nStart <= nR + 1) { nCount = nEnd - nStart; if (nCount <= 0) { pOut[nStart] = pIn[nStart]; return; } nSum = 0; for (i = nStart; i < nEnd; i ++) { nSum += pIn[i]; } nSum = (nSum + (nCount >> 1)) / nCount; for (i = nStart; i < nEnd; i ++) { pOut[i] = nSum; } return; }// first nR len
beg = nStart; end = nStart + nR; if (end > nEnd) end = nEnd; for (i = beg; i < end; i ++) { nSum += pIn[i]; } nCount = end - beg;// from start to start + nR, maybe less than start + nR
if (end >= nEnd-nR) end = nEnd - nR - 1; for (i = nStart; i <= end; i ++) { nSum += pIn[i + nR]; nCount ++; pOut[i] = (nSum + (nCount >> 1)) / nCount; }// from start+nR to end - nR
end = nEnd - nR; for (; i < end; i ++) { nSum += pIn[i + nR] - pIn[i - nR - 1]; pOut[i] = (nSum + nCount / 2) / nCount; }// from end-nR to start + nR
end = nStart + nR + 1; if (end > nEnd) end = nEnd; for (; i < end; i++) { pOut[i] = (nSum + nCount / 2) / nCount; }// the last nR
beg = i; if (beg < nStart + nR + 1) beg = nStart + nR + 1; for (i = beg; i < nEnd; i ++) { nCount --; nSum -= pIn[i - nR - 1]; pOut[i] = (nSum + nCount / 2) / nCount; }return;
}//-------------------------------------------------------
// delete short vertical stroke //------------------------------------------------------- int CArdpsImg::DeleteVtlSmallLine(BYTE* pImg, BYTE* pBuf, int nWidth, int nHeight, int nTh) { if( pImg == NULL || pBuf == NULL ) return 0;int i, j, nTop, nBtm, nLen;
int top, btm; BYTE *pIn, *pIn1, *pb, *pb1; pb = pb1 = pIn = pIn1 = NULL; int hr = 0;top = 0;
btm = nHeight; LONG nBytesPerLine = MYWIDTHBYTES(nWidth * 8); memset(pBuf, 0, nBytesPerLine * nHeight);pIn = pImg + top * nBytesPerLine;
pb = pBuf + top * nBytesPerLine; for (i = top; i < btm; i++) { for (j = 0; j < nWidth; j++, pIn++, pb++) { if (*pIn == 0) { continue; } nTop = i-1; pIn1 = pIn - nBytesPerLine; pb1 = pb - nBytesPerLine; for (; nTop >= 0 && *pIn1 != 0; nTop--, pIn1 -= nBytesPerLine, pb1 -= nBytesPerLine) { *pb1 = *pIn1; *pIn = 0; } nTop++;nBtm = i+1;
pIn1 = pIn + nBytesPerLine; pb1 = pb + nBytesPerLine; for (; nBtm < nHeight && *pIn1 != 0; nBtm++, pIn1 += nBytesPerLine, pb1 += nBytesPerLine) { *pb1 = *pIn1; *pIn1 = 0; } nBtm --; nLen = nBtm - nTop + 1; if (nLen < nTh) { pb1 = pBuf + nTop * nBytesPerLine + j; for (; nTop <= nBtm; nTop++, pb1 += nBytesPerLine) { *pb1 = 0; } } } }memcpy(pImg, pBuf, nBytesPerLine*nHeight);
return 0; }RECT CArdpsImg::GetEdgeImageBoundary(BYTE *pbImage, int nWidth, int nHeight)
{ RECT rect; BYTE *pbIn1, *pbIn2; LONG i, j, m; LONG n, d; int *pnProjX = NULL, *pnProjY = NULL; rect = SetRectValue(0, 0, 0, 0); if( pbImage == NULL ) return rect;LONG nBytesPerLine = MYWIDTHBYTES(nWidth<< 3);
pnProjX = new int [nWidth + nHeight]; if (pnProjX == NULL) { return rect; } pnProjY = pnProjX + nWidth; memset(pnProjX, 0, (nWidth + nHeight) * sizeof(int));for (i = 0, m = 0; i < nHeight; i++, m+= nBytesPerLine )
{ pnProjY[i] = 0; pbIn1 = pbImage + m; for (j = 0; j < nWidth; j++, pbIn1++) { pnProjY[i] += pbIn1[0]; } }pbIn1 = pbImage;
for (i = 0; i < nWidth; i++, pbIn1++) { pbIn2 = pbIn1; pnProjX[i] = 0; for (j = 0; j < nHeight; j++, pbIn2 += nBytesPerLine) { pnProjX[i] += pbIn2[0]; } }d = n = 0;
for (i = 0; i < nHeight; i++) { d += pnProjY[i]; n++; } d = d / (4 * n);rect.top = 0;
for (i = 0; i < nHeight; i++) { if (pnProjY[i] > d) { rect.top = i; break; } } rect.top = rect.top > 1 ? (rect.top - 1) : rect.top;rect.bottom = nHeight - 1;
for (i = nHeight - 1; i >= 0; i--) { if (pnProjY[i] > d) { rect.bottom = i; break; } } rect.bottom = rect.bottom < (nHeight - 2) ? (rect.bottom + 1) : rect.bottom; d = n = 0; for (i = 0; i < nWidth; i++) { d += pnProjX[i]; n++; } d = d / (4 * n);rect.left = 0;
for (i = 0; i < nWidth; i++) { if (pnProjX[i] > d) { rect.left = i; break; } } rect.left = rect.left > 0 ? (rect.left - 1) : rect.left;rect.right = nWidth - 1;
for (i = nWidth - 1; i >= 0; i--) { if (pnProjX[i] > d) { rect.right = i; break; } } rect.right = rect.right < (nWidth - 2) ? (rect.right + 1) : rect.right;if (pnProjX != NULL)
{ delete []pnProjX; pnProjX = NULL; }return rect;
}void CArdpsImg::MoveBin(BYTE *pbIn, int nWidth, int nHeight, RECT rtOld, RECT rtNew, int nMethod)
{ if( !pbIn ) return; LONG lBytesPerLine = MYWIDTHBYTES(nWidth << 3); LONG lImgSize = lBytesPerLine * nHeight; BYTE *pbOut = new BYTE[lImgSize]; if( pbOut == NULL ) return;memset(pbOut, 255, lImgSize * sizeof(BYTE));
LONG i, j, m, n; BYTE *pbTmpIn = NULL; switch (nMethod) { case 1: //水平调整 j = rtOld.right - rtOld.left + 1; for (i = 0, m = 0; i < nHeight; i++, m += lBytesPerLine ) { memcpy(pbOut + rtNew.left+ m, pbIn + rtOld.left + m, j * sizeof(BYTE) ); } break; case 2: //垂直调整 //i = rtOld.bottom - rtOld.top + 1; i = rtNew.top * lBytesPerLine; for( j = rtOld.top, m = j * lBytesPerLine; j <= rtOld.bottom; j++, m += lBytesPerLine) { memcpy(pbOut + i, pbIn + m, lBytesPerLine); i += lBytesPerLine; } break; case 0: //垂直和水平调整 default:i = rtNew.top * lBytesPerLine + rtNew.left;
m = rtOld.top *lBytesPerLine + rtOld.left; n = rtOld.right - rtOld.left + 1; for( j = rtOld.top; j <= rtOld.bottom; j++) { memcpy(pbOut + i, pbIn + m, n * sizeof(BYTE)); i += lBytesPerLine; m += lBytesPerLine; } break; } memcpy( pbIn, pbOut, lImgSize * sizeof(BYTE));if( pbOut )
delete[]pbOut; pbOut = NULL;}
RECT CArdpsImg::GetBinImageBoundary(BYTE *pbImage, int nWidth, int nHeight)
{ RECT rect; BYTE *pbIn1, *pbIn2; LONG i, j, m; LONG n, d; int *pnProjX = NULL, *pnProjY = NULL; rect = SetRectValue(0, 0, 0, 0); if( pbImage == NULL ) return rect;LONG nBytesPerLine = MYWIDTHBYTES(nWidth<< 3);
pnProjX = new int [nWidth + nHeight]; if (pnProjX == NULL) { return rect; } pnProjY = pnProjX + nWidth; memset(pnProjX, 0, (nWidth + nHeight) * sizeof(int));for (i = 0, m = 0; i < nHeight; i++, m+= nBytesPerLine )
{ pnProjY[i] = 0; pbIn1 = pbImage + m; for (j = 0; j < nWidth; j++, pbIn1++) { pnProjY[i] += 255- pbIn1[0]; } pnProjY[i] /= 255; }pbIn1 = pbImage;
for (i = 0; i < nWidth; i++, pbIn1++) { pbIn2 = pbIn1; pnProjX[i] = 0; for (j = 0; j < nHeight; j++, pbIn2 += nBytesPerLine) { pnProjX[i] += 255- pbIn2[0]; } pnProjX[i] /= 255; }d = n = 0;
for (i = 0; i < nHeight; i++) { d += pnProjY[i]; n++; } d = d / (4 * n);rect.top = 0;
for (i = 0; i < nHeight; i++) { if (pnProjY[i] > d) { rect.top = i; break; } } rect.top = rect.top > 1 ? (rect.top - 1) : rect.top;rect.bottom = nHeight - 1;
for (i = nHeight - 1; i >= 0; i--) { if (pnProjY[i] > d) { rect.bottom = i; break; } } rect.bottom = rect.bottom < (nHeight - 2) ? (rect.bottom + 1) : rect.bottom; d = n = 0; for (i = 0; i < nWidth; i++) { d += pnProjX[i]; n++; } d = d / (4 * n);rect.left = 0;
for (i = 0; i < nWidth; i++) { if (pnProjX[i] > d) { rect.left = i; break; } } rect.left = rect.left > 0 ? (rect.left - 1) : rect.left;rect.right = nWidth - 1;
for (i = nWidth - 1; i >= 0; i--) { if (pnProjX[i] > d) { rect.right = i; break; } } rect.right = rect.right < (nWidth - 2) ? (rect.right + 1) : rect.right;if (pnProjX != NULL)
{ delete []pnProjX; pnProjX = NULL; }return rect;
}
RECT CArdpsImg::SetRectValue(int left, int right, int top, int bottom)
{ RECT rect; rect.left = left; rect.right = right; rect.top = top; rect.bottom = bottom;return rect;
} int CArdpsImg::FindEdgeImage(BYTE *pbOutImage, BYTE *image, RECT rtROI, int nWidth) { if( pbOutImage == NULL || image == NULL ) return -1; BYTE *pbIn1, *pbIn2; int i, j, d; int gd, n = 0, k = 0;pbIn2 = pbIn1 = NULL;
int nBytesPerLine = MYWIDTHBYTES(nWidth << 3); gd = n = 0; pbIn1 = image + rtROI.top * nBytesPerLine + rtROI.left; for (i = rtROI.top; i < rtROI.bottom; i++, pbIn1 += nBytesPerLine) { pbIn2 = pbIn1 + EDGE_STEP; for (j = rtROI.left + EDGE_STEP; j < rtROI.right; j++, pbIn2++) { d = pbIn2[-EDGE_STEP] - pbIn2[0]; if (d < 10) { continue; } gd += d; n++; } }if (n < 100)
{ return -1; } gd = gd / n;pbIn1 = image + rtROI.top * nBytesPerLine + rtROI.left;
for (i = rtROI.top; i < rtROI.bottom; i++, pbIn1 += nBytesPerLine) { pbIn2 = pbIn1; for (j = rtROI.left; j < rtROI.right; j++, pbIn2++) { n = (int)(pbIn2 - image); pbOutImage[n] = 0; if (j > EDGE_STEP) { d = pbIn2[-EDGE_STEP] - pbIn2[0]; if (d > gd) { pbOutImage[n] = d; } }if (j < nWidth - EDGE_STEP - 1)
{ d = pbIn2[EDGE_STEP] - pbIn2[0]; if (d > gd && d > pbOutImage[i * nBytesPerLine + j]) { pbOutImage[n] = d; } } } }return 0;
}HDIB CArdpsImg::ReadBinTiff(char* szImgFileName)
{ TIFF *image = NULL; uint32 height, buffsize, bytesPerLine, nImgWidth, nPalleteSize, nFileSize; uint32 row, k, i; HDIB hDIB = NULL;// Open the TIFF image
image = TIFFOpen(szImgFileName, "r"); if( image == NULL ) return hDIB;TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height);
TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &nImgWidth); uint16 bitspersample=1; uint16 samplesperpixel=1; TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bitspersample); //for debug uint16 compression = 0; TIFFGetField(image, TIFFTAG_COMPRESSION, &compression);uint16 photmeric = 0; TIFFGetField(image, TIFFTAG_PHOTOMETRIC, &photmeric);
uint16 bitsperpixel = bitspersample * samplesperpixel;
if( bitsperpixel == 1) nPalleteSize = 2; else if( bitsperpixel == 8 ) nPalleteSize = 256; else if( bitsperpixel == 16) return hDIB; else nPalleteSize = 0;buffsize = TIFFScanlineSize(image);
uint32 buffTotalSize = buffsize * height; BYTE * pbOriImg = new BYTE[buffTotalSize]; if( pbOriImg == NULL ) { TIFFClose(image); return hDIB; }for (row = 0 , k = (height - 1) * buffsize; row < height; row++ , k -= buffsize )
TIFFReadScanline(image, (void*)(pbOriImg + k), row);TIFFClose(image);
/*TIFF *newImg = TIFFOpen("d:\\testread.tif", "w");
TIFFSetField(newImg, TIFFTAG_IMAGELENGTH, height); TIFFSetField(newImg, TIFFTAG_IMAGEWIDTH, nImgWidth); TIFFSetField(newImg, TIFFTAG_SAMPLESPERPIXEL,samplesperpixel); TIFFSetField(newImg, TIFFTAG_BITSPERSAMPLE, bitspersample); TIFFSetField(newImg, TIFFTAG_COMPRESSION, compression); TIFFSetField(newImg, TIFFTAG_PHOTOMETRIC, photmeric); for (row = 0 , k = (height - 1) * buffsize; row < height; row++ , k -= buffsize ) TIFFWriteScanline(newImg, (void*)(pbOriImg + k), row);*/ //TIFFClose(newImg); if( bitsperpixel == 32 ) bytesPerLine = MYWIDTHBYTES(nImgWidth * 24); else bytesPerLine = MYWIDTHBYTES(nImgWidth * bitsperpixel);buffTotalSize = bytesPerLine * height;
nFileSize = buffTotalSize + nPalleteSize * sizeof(RGBQUAD) + sizeof(BITMAPINFOHEADER); hDIB = (HDIB)GlobalAlloc(GHND, nFileSize); if( hDIB == NULL ) { delete []pbOriImg; pbOriImg = NULL; return hDIB; }LPBYTE lpNewDIB = (LPBYTE)GlobalLock(hDIB);
memset( lpNewDIB, 0, nFileSize * sizeof(BYTE));LPBITMAPINFOHEADER pInfo = (LPBITMAPINFOHEADER) lpNewDIB;
pInfo->biSize = sizeof(BITMAPINFOHEADER); pInfo->biWidth = nImgWidth; pInfo->biHeight = height; pInfo->biCompression = BI_RGB; pInfo->biClrUsed = 0; pInfo->biClrImportant = 0; pInfo->biPlanes = 1; pInfo->biSizeImage = buffTotalSize; pInfo->biXPelsPerMeter = 0; pInfo->biYPelsPerMeter = 0; if( bitsperpixel == 32 ) pInfo->biBitCount = 24; else pInfo->biBitCount = bitsperpixel;RGBQUAD *pNewRGBQuad = (RGBQUAD *)( lpNewDIB + sizeof(BITMAPINFOHEADER));
if( bitsperpixel == 1 ) { pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue = 0; pNewRGBQuad->rgbReserved = 0; pNewRGBQuad ++; pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue = 255; pNewRGBQuad->rgbReserved = 0; } else { for( int i = 0; i < nPalleteSize; i++, pNewRGBQuad++ ) { pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = pNewRGBQuad->rgbBlue = i; pNewRGBQuad->rgbReserved = 0; } }BYTE *pbNewImg = lpNewDIB + sizeof(BITMAPINFOHEADER) + nPalleteSize * sizeof(RGBQUAD) ;
if (bitsperpixel == 32) { Img32to24(pbOriImg, pbNewImg, nImgWidth, height); } else if (bitsperpixel == 24) { ReversColors(pbOriImg, pbNewImg, nImgWidth, height); } else { for( i = 0, k = 0, row = 0; i < height; i++, k += bytesPerLine, row += buffsize ) { memcpy(pbNewImg + k, pbOriImg + row, buffsize * sizeof(BYTE)); } } if( pbOriImg ) delete []pbOriImg; pbOriImg = NULL;return hDIB;
}
void CArdpsImg::Img32to24(BYTE *pbImg32, BYTE *pbImg24, int nWidth, int nHeight)
{ if( pbImg32 == NULL || pbImg24 == NULL ) return;int i, j, m, n;
LONG nBytesLine24 = MYWIDTHBYTES(nWidth * 24); BYTE *pbIn = pbImg32; BYTE *pbOut = pbImg24;for( i = 0, m = 0, n = 0; i < nHeight; i++, m += nWidth * 4, n += nBytesLine24 )
{ pbIn = pbImg32 + m; pbOut = pbImg24 + n; for( j = 0; j < nWidth; j++ ) { *pbOut = *(pbIn + 2); *(pbOut + 1) = *(pbIn + 1); *(pbOut + 2) = *(pbIn); pbIn += 4; pbOut += 3; } } } void CArdpsImg::ReversColors(BYTE*pbIn, BYTE *pbOut, int nWidth, int nHeight) { if( pbIn == NULL || pbOut == NULL ) return;int i, j,n, m;
LONG nBytesLine24 = MYWIDTHBYTES(nWidth * 24); BYTE *ptmp = pbIn; BYTE *ptmp2 = pbOut;for( i = 0, n = 0, m = 0; i < nHeight; i++, n += nBytesLine24, m += nWidth * 3 )
{ ptmp = pbIn + m; ptmp2 = pbOut + n; for( j = 0; j < nWidth; j++ ) { *ptmp2 = *(ptmp + 2); *(ptmp2 + 1) = *(ptmp + 1); *(ptmp2 + 2) = *(ptmp); ptmp2 += 3; ptmp += 3; } } }void CArdpsImg::ReversColors(BYTE*pbIn, int nWidth, int nHeight)
{ if( pbIn == NULL ) return;int i, j, m;
LONG nBytesLine24 = MYWIDTHBYTES(nWidth * 24); BYTE *ptmp = pbIn; BYTE bValue = 0; for( i = 0, m = 0; i < nHeight; i++, m += nBytesLine24 ) { ptmp = pbIn + m; for( j = 0; j < nWidth; j++ ) { bValue = *(ptmp + 2); *(ptmp + 2) = *(ptmp); *ptmp = bValue; ptmp += 3; } } }bool CArdpsImg::SaveTiff(char *szImgFileName)
{ if( szImgFileName == NULL ) return false;LPBYTE lpDIB = (LPBYTE) GlobalLock(m_hDib);
if( lpDIB == NULL ) return false;LPBYTE lpBinImg = FindDIBBits(lpDIB);
if( !lpBinImg ) { GlobalUnlock(m_hDib); return false; } uint16 samplesperpixel, bitspersample, photometric, compression;LONG nImgHei = GetHeight();
LONG nImgWid = GetWidth(); WORD nBitCnt = DIBBitCount(lpDIB); if( nBitCnt == 1) { samplesperpixel = 1; bitspersample = 1; photometric = PHOTOMETRIC_MINISBLACK; compression = COMPRESSION_CCITTFAX4; ReversBits(lpBinImg, nImgWid, nImgHei, nBitCnt); } else if (nBitCnt == 8) { samplesperpixel = 1; bitspersample = 8; photometric = 1; compression = COMPRESSION_LZW; } else if (nBitCnt == 24) { samplesperpixel = 3; bitspersample = 8; photometric = 2; compression = COMPRESSION_JPEG; //compression = COMPRESSION_DEFLATE; ReversColors(lpBinImg, nImgWid, nImgHei); } else { GlobalUnlock(m_hDib); return false; }TIFF * newImg = TIFFOpen(szImgFileName, "w");
if( newImg == NULL ) { GlobalUnlock(m_hDib); return false; }TIFFSetField(newImg, TIFFTAG_IMAGELENGTH, nImgHei);
TIFFSetField(newImg, TIFFTAG_IMAGEWIDTH, nImgWid); TIFFSetField(newImg, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); TIFFSetField(newImg, TIFFTAG_BITSPERSAMPLE,bitspersample); TIFFSetField(newImg, TIFFTAG_PHOTOMETRIC, photometric); //if(nBitCnt != 24 ) 只能由程序读取,去掉该注释可以被通用程序读取,压缩比变小。 TIFFSetField(newImg, TIFFTAG_COMPRESSION, compression); TIFFSetField(newImg, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); uint32 row, buffsize, k; buffsize = MYWIDTHBYTES(nImgWid * bitspersample * samplesperpixel ); for (row = 0 , k = (nImgHei - 1) * buffsize; row < nImgHei; row++ , k -= buffsize ) TIFFWriteScanline(newImg, (void*)(lpBinImg + k), row, 0);TIFFClose(newImg);
GlobalUnlock(m_hDib); return true; } void CArdpsImg::ReversBits(BYTE *pbIn, int nWidth, int nHeight, DWORD nBitCnt) {int nBytesPerLine = MYWIDTHBYTES(nBitCnt * nWidth );
BYTE *ptmp = pbIn; for( int i = 0; i < nBytesPerLine * nHeight; i++, ptmp++ ) { *ptmp = 255- (*ptmp); } } bool CArdpsImg::SaveGrayDIB() { LPBITMAPINFOHEADER lpDIBHdr = (LPBITMAPINFOHEADER)GlobalLock(m_hDib);//for color image
LONG nImgHei = GetHeight(); LONG nImgWid = GetWidth(); //for gray image LONG nGrayBytesPerLine = MYWIDTHBYTES( nImgWid << 3 ); LONG nGrayImgSize = nGrayBytesPerLine * nImgHei; LONG nFileSize = nGrayImgSize + lpDIBHdr->biSize + 256 * sizeof(RGBQUAD);//allocate memory for gray image
LPBYTE lpNewDIB = new BYTE[nFileSize]; if( !lpNewDIB ) return false; memset(lpNewDIB, 0, nFileSize*sizeof(BYTE)); LPBITMAPINFOHEADER lpNewDIBHdr = (LPBITMAPINFOHEADER)lpNewDIB; memcpy(lpNewDIBHdr, lpDIBHdr, sizeof(BITMAPINFOHEADER)); GlobalUnlock(m_hDib);lpNewDIBHdr->biBitCount = 8;
lpNewDIBHdr->biCompression = BI_RGB; lpNewDIBHdr->biSizeImage = nGrayImgSize; lpNewDIBHdr->biClrUsed = 256; lpNewDIBHdr->biXPelsPerMeter = 2952; lpNewDIBHdr->biYPelsPerMeter = 2952;//create RGBQUARD
RGBQUAD *pNewRGBQuad = (RGBQUAD*)(lpNewDIB +sizeof(BITMAPINFOHEADER));memset(pNewRGBQuad, 0, 256*sizeof(RGBQUAD));
for( int i = 0; i < 256; ++i ) { pNewRGBQuad->rgbBlue = pNewRGBQuad->rgbRed = pNewRGBQuad->rgbGreen = i; pNewRGBQuad++; } LPBYTE lpDIB = (LPBYTE)GlobalLock(m_hDib); LPBYTE lpSrcImg = FindDIBBits(lpDIB); LPBYTE lpNewImg = lpNewDIB + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);bool bConvert = ConvertBinary2Gray(lpSrcImg, nImgWid, nImgHei, lpNewImg);
GlobalUnlock(m_hDib);
bool bCrate = Create(lpNewDIB); if( lpNewDIB ) delete []lpNewDIB;lpNewDIB = NULL;
return true;
}
转载地址:http://dvfci.baihongyu.com/