我正在尝试编写一种算法,用于检测下图中“RF”和“WOOLF”之间的空间。 我需要类似Scanline for COLUMNS而不是行。 我的算法将扫描每一列是否存在黑色像素,如果发现它将存储'1',否则它将存储'0',因此例如上面的图像可能是: 000001111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111 所以我会知道空间从像素30开始。
答案 0 :(得分:7)
为什么不能通过Scanline访问像素?
for i := 0 to (column count)-1 do begin //enumerate columns
black_pixels:=false
for j := 0 to (row count)-1 do //enumerate scanlines
if PByte(integer(Scanline[j]) + i)^=0 then begin
//black pixels in column i
black_pixels:=true;
break;
end;
end;
(只是一个例子,我不记得使用扫描线的具体细节)
即使您关注地点,也可以设置一个大小数组(列数),并在扫描j时更新它,i:
for j := 0 to (row count)-1 do
for i := 0 to (column count)-1 do
if PByte(integer(Scanline[j]) + i)^=0 then
blackpixels[i] := true;
对于1位图像,数据按位存储在扫描线中(参见this document)。要访问BYTE_VALUE的位k(从0开始计数),请使用:
((BYTE_VALUE shr k) and 1)
根据要求,提供有关其工作原理的其他说明。
“Shl”和“shr”是“向左移动”和“向右移动”操作。他们所做的是将字节内的位移到左侧(最高位侧)和右侧(最低位侧)。例如:
01101101 shr 0 = 01101101
01101101 shr 1 = 00110110
01101101 shr 2 = 00011011
01101101 shr 3 = 00001101
以同样的方式
01101101 shl 0 = 01101101
01101101 shl 1 = 11011010
01101101 shl 2 = 10110100
01101101 shl 3 = 01101000
二进制AND(“C:= A和B”)是一个操作,对于每一位,从A和B得到它的值,并且只有当A和B在同一个地方有1时才将它的值设置为1
例如:
01101101 and
00000000 =
00000000 (B has no 1's at all)
01101101 and
11111111 =
01101101 (B has all 1's, so every 1 from A is transferred to C)
01101101 and
11001100 =
01001100
因此((BYTE_VALUE shr(i-1))和1)的作用是:
首先,将BYTE_VALUE(i-1)位向右移动,从而使其位于最右边的第i位。但是新的BYTE_VALUE仍然可以在其左侧具有不相关的位。
然后,将除最新的位之外的所有位都清零。
例如,如果我们想知道01101101的最右边第5位,我们将其缩小为4:
01101101 shr 4 = 00000110
但是尽管最右边的位为零,但整个值仍然不为零。我们和1 == 00000001:
00000110 and 00000001 = 00000000 = 0
回到主题。当您的列按位打包时,这就是您枚举它们的方式:
setLength(blackpixels, ColumnCount);
for i := 0 to ColumnCount - 1 do
blackpixels[i] := false;
for j := 0 to RowCount-1 do
for i := 0 to ColumnCount div 8-1 do begin
byte_value := PByte(integer(Bitmap.Scanline[j]) + i)^; //read the byte which contains 8 columns
for k := 0 to 7 do
if ((byte_value shr (7-k)) and 1)=0 then
blackpixels[i*8+k] := true;
end;
以下是工作示例,以防万一:
//Assuming img is declared as img: TImage;
//mm is declared as mm: TMemo;
var blackpixels: array of boolean;
i, j, k: integer;
byte_value: byte;
RowCount, ColumnCount: integer;
Bitmap: TBitmap;
s: string;
begin
RowCount := img.Picture.Bitmap.Height;
ColumnCount := img.Picture.Bitmap.Width;
Bitmap := img.Picture.Bitmap;
setLength(blackpixels, ColumnCount);
for i := 0 to ColumnCount - 1 do
blackpixels[i] := false;
if Bitmap.PixelFormat=pf1Bit then begin
for j := 0 to RowCount-1 do
for i := 0 to ColumnCount div 8-1 do begin
byte_value := PByte(integer(Bitmap.Scanline[j]) + i)^; //read the byte which contains 8 columns
for k := 0 to 7 do
if ((byte_value shr (7-k)) and 1)=0 then //(7-k) because pixels seems to be stored inside of the byte "left-to-right" (highest to lowest)
blackpixels[i*8+k] := true;
end;
end else
raise Exception.Create('Invalid pixel format');
//Print array
if ColumnCount > 0 then
s := BoolToStr(blackpixels[0], false)
else s := '';
for i := 1 to ColumnCount - 1 do
s := s + ', ' + BoolToStr(blackpixels[i], false);
s := '(' + s + ')';
mm.Lines.Add(s);