将图像转换为矩阵

时间:2013-03-09 16:12:18

标签: image delphi matrix bmp

我正在尝试将图像(比方说黑白)转换为矩阵(其中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;

但它给了我错误的结果。

任何想法?

3 个答案:

答案 0 :(得分:12)

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

<强>第一

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 =黑色和1 =白色”,但显然你做的却相反!

第四,您尝试访问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.BeginUpdateMemo1.Lines.EndUpdate,即可获得更快的速度。

答案 1 :(得分:5)

以下过程将输入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;

答案 2 :(得分:-1)

备注行位置下降,但是你的循环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;