【问题标题】:Delphi write pixel colors to memoDelphi 将像素颜色写入备忘录
【发布时间】:2015-03-17 11:26:58
【问题描述】:

我想做一个程序,可以把我的 TImage 像素 rgb 颜色写入备忘录,程序不知道分辨率。

那么如何将每个像素颜色恢复为字符串变量 (R,G,B)?

代码

var 
Image_width,Image_height,x,y,i,i2:integer;
Colors:TColor;

begin
Image_width:=Image1.Width;
Image_height:=Image1.Height;
memo1.text:='$image_width=*'+IntToStr(Image_Width)+
            '$$image_height='+IntToStr(Image_Height)+'*$';
x:=1;
y:=1;
for i := 1 to Image_width do begin
 for i2 := 1 to Image_height do begin
  Colors:=Image1.Canvas.Pixels[x,y];
  memo1.Text:=memo1.Text+ColorToString(Colors);
  y:=y+1;
 end;
 x:=x+1
end;
end

|已编辑|

procedure TForm1.Button2Click(Sender: TObject);
var
Image_width,Image_height,x,y:integer;
Colors:TColor;
s:string;
begin

 Image_width:=Image1.Width;
 Image_height:=Image1.Height;



 memo1.text:='$image_width=*'+IntToStr(Image_Width)
            +'*$ $image_height=*'+IntToStr(Image_Height)+'*$';


x:=0;
y:=0;

memo1.Lines.BeginUpdate;
for x := 0 to Image_width do begin
    for y := 0 to Image_height do begin
     Colors:=Image1.Canvas.Pixels[x,y];
     memo1.Text:=Memo1.Text+ColorToString(Colors);

    end;
memo1.Lines.EndUpdate;
end;
end;

它完成非常慢,我认为 19 秒与 640x480 图片。 在程序准备好并放入 memo1 后,我在 memo1 中看到了一些东西,但程序再次“没有响应”..

我尝试使用 s 变量,程序也这样做。

【问题讨论】:

  • 使用 TBitmap 的 Scanline 属性读取像素。或来自TImage.Canvas.Pixels[] 属性。后者会慢一些。
  • 您可以编写一个record helper for TRGBTriple 并实现一个ToString 方法。剩下的就是迭代ScanLined 列并调用该方法,
  • @Close voters:我不认为寻求调试帮助的问题(“为什么这段代码不起作用?”) 是正确的选择。这个原因应该用于寻求调试帮助的问题,而不是用于为我编写代码帖子。
  • 这个问题太深奥了:有多个解,还有多个子解。你为什么不把这个问题分解成小块?比如:如何获取像素的颜色,如何将颜色转换和格式化为字符串,如何将字符串添加到备忘录中,如何格式化/概述备忘录中的字符串等等......
  • 对您编辑的代码的评论。 for 循环应该分别转到 Image_width-1Image_height-1memo1.Lines.EndUpdate; 放错了位置。它应该在for x := 0 to Image_width do beginend; 之后。如果您使用了代码格式化 (Ctrl-D),它会很容易被发现。正如我所说,反复连接 memo1.Text 非常慢。使用建议的其他解决方案。但是你真的应该解释一下为什么你甚至想把这种大小的图像转换成一个很长的字符串?

标签: windows delphi delphi-xe7


【解决方案1】:

第一次更正,像素从 0, 0 开始。而不是像你一样的 1, 1。替换for循环前的初始值如下:

  x := 0; // not 1;
  y := 0; // not 1;

实际上,此时不需要分配y,我们很快就会看到。

第二次更正,仔细观察内部for 循环。 i2 从 1 步进到 Image_height 并且 y 在循环的每一轮中递增,这没关系。然后对外部循环的访问增加 x 并且我们返回到内部循环。 y 会发生什么?它从之前停止的地方继续,而它应该首先重置为 0。解决方法是添加一行,如下所示。这也是为什么上面的分配是多余的。

  for i := 1 to Image_width do
  begin
    y := 0; // Add this line
    for i2 := 1 to Image_height do
    begin

改进建议

不清楚resolution 未知是什么意思。如果您的意思是颜色深度或每像素位数,那么您使用pixels 的方法可能更直接。否则,正如 cmets 中所建议的,您可以考虑使用扫描线而不是像素来更快地访问实际位图数据。优秀文章见:How to use ScanLine property for 24-bit bitmaps?

反复将颜色字符串连接到Text 属性非常慢。事实上,对于 64 x 64 像素的图像,它是如此缓慢,以至于我等不及它运行到最后。为了加快速度,您可以使用单独的 string 变量来连接颜色字符串

  Colors := Image1.Canvas.Pixels[x, y];
  s := s + ColorToString(Colors);

然后在循环连接到 Text 属性之后

  Memo1.Text := Memo1.Text + s;

如果您打算将每个像素颜色字符串作为新行添加到备忘录中,您可以改用 Add 方法

  Colors := Image1.Canvas.Pixels[x, y];
  Memo1.Lines.Add(ColorToString(Colors));

Memo1.Lines.BeginUpdate;Memo1.Lines.EndUpdate; 围绕for 循环进一步提高了速度。

最后,您也可以使用xy 作为循环控制变量,或者使用ii2 作为像素索引。我会放弃ii2,并使用xy 作为循环控制变量和像素索引。但我留给你决定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多