Delphi的>垂直扫描线? (获取列而不是行?)

时间:2010-11-02 10:10:11

标签: delphi image-processing

alt text

我正在尝试编写一种算法,用于检测下图中“RF”和“WOOLF”之间的空间。 我需要类似Scanline for COLUMNS而不是行。 我的算法将扫描每一列是否存在黑色像素,如果发现它将存储'1',否则它将存储'0',因此例如上面的图像可能是: 000001111111111111111111100000000000000000000000011111111111111111111111111111111111111111111111111 所以我会知道空间从像素30开始。

1 个答案:

答案 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);