我正在尝试将图像(比方说黑白)转换为矩阵(其中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;
但它给了我错误的结果。
任何想法?
答案 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
属性。有关详细信息,请参阅this或that或something else。
此外,只需在更新备忘录控件之后添加Memo1.Lines.BeginUpdate
和Memo1.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;