Delphi 如何计算位图的闭合裁剪矩形?
我需要根据给定的背景色键计算位图的闭合裁剪矩形。在下面的图片中,你可以看到什么是接近的作物。左侧是源,右侧是闭合裁剪的输出: 如您所见,我需要找到与背景颜色不同的最上面、最左边、最下面和最右边的像素,以构建闭合裁剪矩形。那么,如何找到这些不同的外部像素来获得接近的裁剪矩形呢?或者,换句话说,如何计算位图的闭合裁剪矩形?您可以使用此代码(您也可以按照本文的说明进行操作):Delphi 如何计算位图的闭合裁剪矩形?,delphi,image-processing,Delphi,Image Processing,我需要根据给定的背景色键计算位图的闭合裁剪矩形。在下面的图片中,你可以看到什么是接近的作物。左侧是源,右侧是闭合裁剪的输出: 如您所见,我需要找到与背景颜色不同的最上面、最左边、最下面和最右边的像素,以构建闭合裁剪矩形。那么,如何找到这些不同的外部像素来获得接近的裁剪矩形呢?或者,换句话说,如何计算位图的闭合裁剪矩形?您可以使用此代码(您也可以按照本文的说明进行操作): procedure CalcCloseCrop(ABitmap:TBitmap;const ABackColor:TCol
procedure CalcCloseCrop(ABitmap:TBitmap;const ABackColor:TColor;
外冠:TRect);
变量
X:整数;
Y:整数;
颜色:TColor;
像素:PRGB3P;
RowClean:布尔值;
LastClean:布尔;
开始
如果是ABitmap.PixelFormat PF24位,则
引发异常。创建('位深度不正确,位图必须为24位!');
LastClean:=假;
ACropRect:=Rect(ABitmap.Width,ABitmap.Height,0,0);
对于Y:=0到ABitmap.Height-1 do
开始
RowClean:=真;
像素:=ABitmap.ScanLine[Y];
对于X:=0到ABitmap.Width-1 do
开始
颜色:=RGB(Pixel.rgbtRed、Pixel.rgbtGreen、Pixel.rgbtBlue);
如果颜色是ABackColor那么
开始
RowClean:=False;
如果XACropRect.那么
右顶点:=X+1;
结束;
像素公司;
结束;
如果不干净的话
开始
如果不干净的话
开始
LastClean:=真;
顶点:=Y;
结束;
如果Y+1>ACropRect.Bottom,则
顶点底部:=Y+1;
结束;
结束;
如果我是空的,那么
开始
如果ACropRect.Left=ABitmap.Width,则
左顶点:=0;
如果ACropRect.Top=ABitmap.Height,则
顶点:=0;
如果ACropRect.Right=0,则
ACropRect.Right:=绝对贴图宽度;
如果ACropRect.Bottom=0,则
ACropRect.Bottom:=ABitmap.Height;
结束;
结束;
程序TForm1.按钮1单击(发送方:TObject);
变量
R:TRect;
位图:TBitmap;
开始
CalcCloseCrop(Image1.Picture.Bitmap,$00FFA749,R);
位图:=TBitmap.Create;
尝试
位图.设置大小(R.宽度,R.高度);
Bitmap.Canvas.CopyRect(Rect(0,0,R.宽度,R.高度),Image1.Canvas,R);
Image1.Picture.Bitmap.Assign(位图);
最后
位图。免费;
结束;
结束;
我尝试了大卫最近帮我解答的一些问题的混合代码:我想我能理解,但不是真的。我应该能够调整ResizeBitmapCanvas过程来实现这一点,但我不能,我很容易被搞糊涂。@Blobby一种方法是从位图的每一侧开始,减小循环变量,直到找到一个与背景颜色不同的像素,对每一侧重复这个过程,瞧,你给自己弄了个自动裁剪机tool@Dorin,您可以在一个扫描线通过槽中完成,您只需记住限制;-)@TLama我不确定,例如立方体可能有右“边”倾斜(不是直的),因此,你最终会得到非常糟糕的裁剪,可能是我缺少了一些东西(:@Dorin,不,在这种情况下,你只需要记住右上一个脏像素的位置。你会从上到下扫描,当你找到一个离左更远的脏像素时,你会存储该像素的位置等。非常棒的东西TLama,不会从这一个拿走积分;)我只希望我不仅能理解你的答案,还能理解其他许多问题。编辑:位图上的像素是否被一个不可见的框(边界框)包围正如我最初所想的那样?如果是通过使用Rect发现的?我将尝试对此进行评论,但在回顾之后。关于不可见框,您是指裁剪图像周围的一些空白,对吗?我将添加一些,但是如果第一个(非背景)像素位于位置[0;0]上会怎么样,你想把它扩展到图像大小后面,并用ABackColor填充这个外部空间吗?@TLama看到这个问题了,我编辑了它,试图展示我所说的不可见边界框的确切含义(甚至有这样的东西吗??)。我想如果第一个像素是[0,0]这样就不会发生裁剪。我明白了,所以裁剪结果周围只有一个额外的空白。关于左上角的第一个像素情况,你是对的,不会有任何裁剪,但是即使在这种情况下,你想用该空间扩展图像吗?不过,最简单的方法是获得紧密裁剪矩形(使用CalcCloseCrop),创建一个临时位图,大小为ACropRect+边界空间,用ABackColor填充,并将ACropRect区域从源图像复制到该临时位图的中心。然后从该临时位图生成结果:-)尝试查看。ScanLine
函数的结果是指向表示线的第一个像素的第一个颜色结构的指针。此结构由用于表示单个像素的字节值计数组成。如果您有24位图像,您将使用PRGBTriple(指向TRGBTriple记录的指针,其中包含3个字节),因为24位图像像素存储为3个字节,如蓝绿色和红色。如果您有8位映像,则只使用PByte(指向单个字节的指针)。Inc(像素)此示例中的代码>表示。。
procedure CalcCloseCrop(ABitmap: TBitmap; const ABackColor: TColor;
out ACropRect: TRect);
var
X: Integer;
Y: Integer;
Color: TColor;
Pixel: PRGBTriple;
RowClean: Boolean;
LastClean: Boolean;
begin
if ABitmap.PixelFormat <> pf24bit then
raise Exception.Create('Incorrect bit depth, bitmap must be 24-bit!');
LastClean := False;
ACropRect := Rect(ABitmap.Width, ABitmap.Height, 0, 0);
for Y := 0 to ABitmap.Height-1 do
begin
RowClean := True;
Pixel := ABitmap.ScanLine[Y];
for X := 0 to ABitmap.Width - 1 do
begin
Color := RGB(Pixel.rgbtRed, Pixel.rgbtGreen, Pixel.rgbtBlue);
if Color <> ABackColor then
begin
RowClean := False;
if X < ACropRect.Left then
ACropRect.Left := X;
if X + 1 > ACropRect.Right then
ACropRect.Right := X + 1;
end;
Inc(Pixel);
end;
if not RowClean then
begin
if not LastClean then
begin
LastClean := True;
ACropRect.Top := Y;
end;
if Y + 1 > ACropRect.Bottom then
ACropRect.Bottom := Y + 1;
end;
end;
if ACropRect.IsEmpty then
begin
if ACropRect.Left = ABitmap.Width then
ACropRect.Left := 0;
if ACropRect.Top = ABitmap.Height then
ACropRect.Top := 0;
if ACropRect.Right = 0 then
ACropRect.Right := ABitmap.Width;
if ACropRect.Bottom = 0 then
ACropRect.Bottom := ABitmap.Height;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
R: TRect;
Bitmap: TBitmap;
begin
CalcCloseCrop(Image1.Picture.Bitmap, $00FFA749, R);
Bitmap := TBitmap.Create;
try
Bitmap.SetSize(R.Width, R.Height);
Bitmap.Canvas.CopyRect(Rect(0, 0, R.Width, R.Height), Image1.Canvas, R);
Image1.Picture.Bitmap.Assign(Bitmap);
finally
Bitmap.Free;
end;
end;