【问题标题】:Convert image to matrix [closed]将图像转换为矩阵 [关闭]
【发布时间】:2013-03-09 16:12:17
【问题描述】:

我正在尝试将图像(比如说黑白)转换为矩阵(其中 0 = 黑色,1 = 白色)

我用这段代码试过了:

procedure TForm1.Button1Click(Sender: TObject);
type
  tab = array[1..1000,1..1000] of byte;
var i,j: integer;
    s : string;
    image : TBitmap;
    t : tab;
begin
  image := TBitmap.Create;
  image.LoadFromFile('c:\image.bmp');

  s := '';
  for i := 0 to image.Height do
  begin
     for j := 0 to image.Width do
     begin
      if image.Canvas.Pixels[i,j] = clWhite then
        t[i,j] := 0
      else
        t[i,j] := 1;

     end;
  end;
  for i := 0 to image.Height do
  begin
    for j := 0 to image.Width do
     begin
      s:=s + IntToStr(t[i,j]);
     end;
     Memo1.Lines.Add(s);
     s:='';
  end;
end;

但它给了我错误的结果。

有什么想法吗?

【问题讨论】:

  • Nooo,Pixels 又回来了。
  • 它会非常慢...当您访问大面积像素时,您应该使用TBitmap.ScanLine 属性。
  • @Roro:除了三个明显的错误,正如我在回答中指出的那样。
  • “很难说这里要问什么。”好吧,我很确定这是“代码有什么问题?”。 “......不能以目前的形式得到合理的回答”所以我和 TLama 的回答都不好? “模棱两可、模糊、不完整、过于宽泛或理论化”?真的吗?我不这么认为。
  • 为什么这个问题被关闭了?似乎是一个有效的。

标签: image delphi matrix bmp


【解决方案1】:

您的代码中有五个错误和另外两个问题!

第一

for i := 0 to image.Height do

必须替换为

for i := 0 to image.Height - 1 do

(为什么?)同样,

for j := 0 to image.Width do

必须替换为

for j := 0 to image.Width - 1 do

第二Pixels 数组接受参数[x, y],而不是[y, x]。因此,您需要更换

image.Canvas.Pixels[i,j]

通过

image.Canvas.Pixels[j,i]

第三,你写了“0 = black and 1 = white”,但显然你做了相反的事情!

第四,您尝试访问t[0, 0],即使您的矩阵从1 开始索引。使用array[0..1000,0..1000] of byte; 来解决这个问题。

第五,你有内存泄漏(image 没有被释放——使用try..finally)。

还有,最好使用动态数组:

type
  TByteMatrix = array of array of byte;

var
  mat: TByteMatrix;

然后你开始

SetLength(mat, image.Height - 1, image.Width - 1);

如果您希望它索引[y, x],否则相反。

最后,在这种情况下,您根本不应该使用Pixels 属性,因为它非常慢。相反,请使用 Scanline 属性。有关详细信息,请参阅 thisthatsomething else

此外,您只需在更新备忘录控件之前添加Memo1.Lines.BeginUpdate 和在更新后添加Memo1.Lines.EndUpdate 即可获得很多速度。

【讨论】:

    【解决方案2】:

    以下过程将输入 ABitmap 位图转换为多维 AMatrix 字节数组,它表示像素,其中 0 值表示白色像素,1 表示任何其他颜色:

    type
      TPixelMatrix = array of array of Byte;
    
    procedure BitmapToMatrix(ABitmap: TBitmap; var AMatrix: TPixelMatrix);
    type
      TRGBBytes = array[0..2] of Byte;
    var
      I: Integer;
      X: Integer;
      Y: Integer;
      Size: Integer;
      Pixels: PByteArray;
      SourceColor: TRGBBytes;
    const
      TripleSize = SizeOf(TRGBBytes);
    begin
      case ABitmap.PixelFormat of
        pf24bit: Size := SizeOf(TRGBTriple);
        pf32bit: Size := SizeOf(TRGBQuad);
      else
        raise Exception.Create('ABitmap must be 24-bit or 32-bit format!');
      end;
    
      SetLength(AMatrix, ABitmap.Height, ABitmap.Width);
      for I := 0 to TripleSize - 1 do
        SourceColor[I] := Byte(clWhite shr (16 - (I * 8)));
    
      for Y := 0 to ABitmap.Height - 1 do
      begin
        Pixels := ABitmap.ScanLine[Y];
        for X := 0 to ABitmap.Width - 1 do
        begin
          if CompareMem(@Pixels[(X * Size)], @SourceColor, TripleSize) then
            AMatrix[Y, X] := 0
          else
            AMatrix[Y, X] := 1;
        end;
      end;
    end;
    

    此过程将多维 AMatrix 字节数组打印到 AMemo 备忘录框:

    procedure ShowPixelMatrix(AMemo: TMemo; const AMatrix: TPixelMatrix);
    var
      S: string;
      X: Integer;
      Y: Integer;
    begin
      AMemo.Clear;
      AMemo.Lines.BeginUpdate;
      try
        AMemo.Lines.Add('Matrix size: ' + IntToStr(Length(AMatrix[0])) + 'x' +
          IntToStr(Length(AMatrix)));
        AMemo.Lines.Add('');
    
        for Y := 0 to High(AMatrix) do
        begin
          S := '';
          for X := 0 to High(AMatrix[Y]) - 1 do
          begin
            S := S + IntToStr(AMatrix[Y, X]);
          end;
          AMemo.Lines.Add(S);
        end;
      finally
        AMemo.Lines.EndUpdate;
      end;
    end;
    

    以及上述程序的用法:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      Bitmap: TBitmap;
      PixelMatrix: TPixelMatrix;
    begin
      Bitmap := TBitmap.Create;
      try
        Bitmap.LoadFromFile('d:\Image.bmp');
        BitmapToMatrix(Bitmap, PixelMatrix);
      finally
        Bitmap.Free;
      end;
      ShowPixelMatrix(Memo1, PixelMatrix);
    end;
    

    上述BitmapToMatrix 过程的扩展允许您指定AMinIntensity 参数给定的luminance 级别将像素视为非白色。

    AMinIntensity 值越接近 0,越亮的像素被视为非白色。这允许您使用颜色强度容差(例如,更好地识别抗锯齿文本):

    procedure BitmapToMatrixEx(ABitmap: TBitmap; var AMatrix: TPixelMatrix;
      AMinIntensity: Byte);
    type
      TRGBBytes = array[0..2] of Byte;
    var
      X: Integer;
      Y: Integer;
      Gray: Byte;
      Size: Integer;
      Pixels: PByteArray;
    begin
      case ABitmap.PixelFormat of
        pf24bit: Size := SizeOf(TRGBTriple);
        pf32bit: Size := SizeOf(TRGBQuad);
      else
        raise Exception.Create('ABitmap must be 24-bit or 32-bit format!');
      end;
    
      SetLength(AMatrix, ABitmap.Height, ABitmap.Width);
    
      for Y := 0 to ABitmap.Height - 1 do
      begin
        Pixels := ABitmap.ScanLine[Y];
        for X := 0 to ABitmap.Width - 1 do
        begin
          Gray := 255 - Round((0.299 * Pixels[(X * Size) + 2]) +
            (0.587 * Pixels[(X * Size) + 1]) + (0.114 * Pixels[(X * Size)]));
    
          if Gray < AMinIntensity then
            AMatrix[Y, X] := 0
          else
            AMatrix[Y, X] := 1;
        end;
      end;
    end;
    

    【讨论】:

    • 请注意,上面的代码是未经测试的,只是在浏览器中编写的......我稍后会审查它(我希望)。
    • 如果图像是黑白的,它实际上可能是 1 位的!如果是的话,将其转换为字节/文本矩阵就更容易了。
    • @yassine_hell,您需要支持哪些像素格式? Andreas 认为的位图是 1 位的吗?如果是这样,您还需要使用哪些其他像素格式?
    • 不,我猜它是 32 位,因为我实际上是在处理白色背景和浅蓝色文本。我只是提到了黑色和白色,以便更容易理解
    • (大多数 BMP 是 24 位的。)
    【解决方案3】:

    备注行位置下降,但您的循环 image.height 首先将在备注中反转结果,尝试此代码

    procedure TForm1.Button1Click(Sender: TObject);
    var i,j: integer;
        s : string;
        image : TBitmap;
    begin
      image := TBitmap.Create;
      image.LoadFromFile('c:\image.bmp');
    
      s := '';
      for i := 0 to image.width-1 do
      begin
         for j := 0 to image.Height-1 do
         begin
          if image.Canvas.Pixels[i,j] = clWhite then
            s := s+'0'
          else
            s := s+'1';
         end;
         memo1.Lines.Add(s);
         s:='';
      end;
    end;
    

    【讨论】:

    • (1) 越界。 (2) 白色 = 0? (3) 内存泄漏 [还有:没有开始/结束更新?]
    • 我的答案已经在我的电脑上测试过了。和 image.bitmap 相同的备忘录视图。如果该代码变慢请更改为扫描线
    • 嗯,越界错误很明显!就个人而言,我更喜欢可以保证工作的代码,而不是几乎可以靠运气工作的代码。 更新:这样更好。
    • 对不起,我忘了加-1
    • @Andreas : for (2) white = 0?,简单的方法只是把整数改成字符串,请看他想要的最终结果
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多