问题描述
我仅在Windows(AutoHotkey)上编程,并且主要使用其win32 API。 我想将GDI位图(32位DIB)转换为灰度。 我使用GetObject()获得一个BITMAP结构,并将bmBITS及其大小传递给以下函数
int ToGrayscale(unsigned char * s,int n)
{
float b,g,r,y;
for (int i=0; i<n; i+=4)
{
b = (float) s[i+0];
g = (float) s[i+1];
r = (float) s[i+2];
y = (0.299 * r) + (0.587 * g) + (0.114 * b);
s[i+0] = s[i+1] = s[i+2] = (unsigned char)y;
}
return 1;
}
上面是完整的代码。我用Pelles C将其编译为.obj,然后从.obj中提取机器代码 并从AutoHotkey语言调用/使用该机器代码。
机器代码在调用时给我访问冲突错误。
s[i+0] = s[i+1] = s[i+2] = 0;
工作正常,并将图像填充为黑色,但是我想用y(灰度值)转换像素。 正确的方法是什么?
我不确定是否提供了足够的信息。请询问/建议,我会进行更新。
编辑1: 我在c文件中添加了另一个工作函数ToBlack()。
int ToBlack(unsigned char * s,int n)
{
for (int i=0; i<n; i+=4)
{
s[i+0] = s[i+1] = s[i+2] = 0;
}
return 1;
}
int ToGrayscale(unsigned char * s,y;
for (int i=0; i<n; i+=4)
{
b = (float) s[i+0];
g = (float) s[i+1];
r = (float) s[i+2];
y = (0.299 * r) + (0.587 * g) + (0.114 * b);
s[i+0] = s[i+1] = s[i+2] = (unsigned char)y;
}
return 1;
}
源位图是具有单个ARGB颜色FFAABBCC的2x2 32位不透明位图 bmBITS大小为16个字节,数据的十六进制表示为 CCBBAAFFCCBBAAFFCCBBAAFFCCBBAAFF
ToBlack()工作正常,当我在运行机器代码后检查bmBITS时, 我得到以下结果-正确。
ToBlack(bmBITS,16)结果: 000000FF000000FF000000FF000000FF
ToBlack(bmBITS,12)结果: 000000FF000000FF000000FFCCBBAAFF
ToBlack(bmBITS,8)结果: 000000FF000000FFCCBBAAFFCCBBAAFF
ToBlack(bmBITS,4)结果: 000000FFCCBBAAFFCCBBAAFFCCBBAAFF
使用ToGrayscale(bmBITS,16)时,数据保持不变。 我猜测当分配y时会发生崩溃。
解决方法
我找到了访问冲突错误的来源。 机器代码不可移植。 对于以下C代码
int ToGrayscale(unsigned char * s,int n)
{
float b,g,r,y;
for (int i=0; i<n; i+=4)
{
b = (float) s[i+0];
g = (float) s[i+1];
r = (float) s[i+2];
y = (0.299 * r) + (0.587 * g) + (0.114 * b);
s[i+0] = s[i+1] = s[i+2] = (unsigned char)y;
}
return 1;
}
.obj转储如下:
Dump of D:\AhkScripts\AHK-003\ToGrayscale.obj
File type: OBJ
_ToGrayscale:
[00000000] 55 push ebp
[00000001] 89E5 mov ebp,esp
[00000003] 83EC10 sub esp,10
[00000006] 56 push esi
[00000007] 8B5508 mov edx,dword ptr [ebp+8]
[0000000A] 8B4D0C mov ecx,dword ptr [ebp+C]
[0000000D] 85C9 test ecx,ecx
[0000000F] 7E6C jle 0000007D
[00000011] 31F6 xor esi,esi
[00000013] 0FB60432 movzx eax,byte ptr [edx+esi]
[00000017] 50 push eax
[00000018] DB0424 fild dword ptr [esp]
[0000001B] 58 pop eax
[0000001C] D95DFC fstp dword ptr [ebp-4]
[0000001F] 0FB6443201 movzx eax,byte ptr [edx+esi+1]
[00000024] 50 push eax
[00000025] DB0424 fild dword ptr [esp]
[00000028] 58 pop eax
[00000029] D95DF8 fstp dword ptr [ebp-8]
[0000002C] 0FB6443202 movzx eax,byte ptr [edx+esi+2]
[00000031] 50 push eax
[00000032] DB0424 fild dword ptr [esp]
[00000035] 58 pop eax
[00000036] D95DF4 fstp dword ptr [ebp-C]
[00000039] D945F4 fld dword ptr [ebp-C]
[0000003C] DC0D00000000 fmul qword ptr [@37]
[00000042] D945F8 fld dword ptr [ebp-8]
[00000045] DC0D00000000 fmul qword ptr [@38]
[0000004B] DEC1 faddp st(1),st
[0000004D] D945FC fld dword ptr [ebp-4]
[00000050] DC0D00000000 fmul qword ptr [@39]
[00000056] DEC1 faddp st(1),st
[00000058] D95DF0 fstp dword ptr [ebp-10]
[0000005B] D945F0 fld dword ptr [ebp-10]
[0000005E] E800000000 call ___ftouc
[00000063] 88443202 mov byte ptr [edx+esi+2],al
[00000067] D945F0 fld dword ptr [ebp-10]
[0000006A] E800000000 call ___ftouc
[0000006F] 88443201 mov byte ptr [edx+esi+1],al
[00000073] 880432 mov byte ptr [edx+esi],al
[00000076] 83C604 add esi,4
[00000079] 39CE cmp esi,ecx
[0000007B] 7C96 jl 00000013
[0000007D] B801000000 mov eax,1
[00000082] 5E pop esi
[00000083] 89EC mov esp,ebp
[00000085] 5D pop ebp
[00000086] C3 ret
SUMMARY
28 .drectve
18 .rdata
87 .text
似乎有一个名为 ___ ftouc 的不存在的函数的调用 是浮动到未签名的字符,并且只有在链接时才可用。 (如果我错了,请纠正我)
解决方案?以不需要类型转换的方式进行数学运算。 下面的代码在x86 / x64中可以正常工作。
void ToGrayscale(unsigned char * s,int n)
{
for (int i=0; i<n; i+=4)
s[i+0] = s[i+1] = s[i+2] = ( (s[i+0]*114) + (s[i+1]*587) + (s[i+2]*299) ) / 1000;
}