Hi,
first of all thanks for the great library!!
However I got a problem resizing images because I always get rectangles in areas with the same or very similar color (such as the sky, wall etc). The rest of image (for example faces) are perfect. I used bicubic filter, I also tried to change the hardcoded value in the following code (in Imaging.pas, line 2334) to use other filters (sfGaussian, sfLanczos, sfMitchell) but the only difference was that the size of the rectangles has changed a little.
rfBicubic: StretchResample(WorkImage, SrcX, SrcY, SrcWidth, SrcHeight,
DstImage, DstX, DstY, DstWidth, DstHeight, sfCatmullRom);
Am I doing something wrong or is this a bug? I used to use the attached unit in the previous versions of my program and that one produces much better results (you can compare, all attached).
Source: JPEG (from a camera)
Resolution: 13 MPix
The original picture is too large so you can get it from here: http://www.ildam.cz/foto/IMG_3692.JPG (http://www.ildam.cz/foto/IMG_3692.JPG)
Please help!
Thanks, David
I ask, I answer. I like this forum. :-)
Anyway, I found a problem in function StretchResample (ImagingFormats.pas). This function rounds the Weights which speeds up the process a bit but produces the ugly rectangles in the result. I tried to modify the function and it seems the result is much better now. Please consider implementing this into the next version of the library. Changed lines are marked with "DMA".
var IWeightR, IAccumAR, IAccumRR, IAccumGR, IAccumBR : single;
...
for J := 0 to DstHeight - 1 do
begin
ClusterY := MapY[J];
for X := XMinimum to XMaximum do
begin
IAccumAR := 0.0; // DMA
IAccumRR := 0.0; // DMA
IAccumGR := 0.0; // DMA
IAccumBR := 0.0; // DMA
for Y := 0 to Length(ClusterY) - 1 do
begin
// IWeight := Round(256 * ClusterY[Y].Weight); // DMA - do not use
IWeightR:= 256*ClusterY[Y].Weight; // DMA, remove rounding
CopyPixel(
@PByteArray(SrcImage.Bits)[(ClusterY[Y].Pos * SrcImage.Width + X) * Info.BytesPerPixel],
@SrcColor, Info.BytesPerPixel);
IAccumBR := IAccumBR + SrcColor.B * IWeightR; // DMA, use single instead of integer
IAccumGR := IAccumGR + SrcColor.G * IWeightR; // DMA, use single instead of integer
IAccumRR := IAccumRR + SrcColor.R * IWeightR; // DMA, use single instead of integer
IAccumAR := IAccumAR + SrcColor.A * IWeightR; // DMA, use single instead of integer
end;
with LineBufferInt[X - XMinimum] do
begin
A := round(IAccumAR); // DMA, round single
R := round (IAccumRR);// DMA, round single
G := round (IAccumGR);// DMA, round single
B := round (IAccumBR);// DMA, round single
end;
end;
DstLine := @PByteArray(DstImage.Bits)[((J + DstY) * DstImage.Width + DstX)* Info.BytesPerPixel];
for I := 0 to DstWidth - 1 do
begin
ClusterX := MapX[I];
IAccumAR := 0.0; // DMA, use single
IAccumRR := 0.0; // DMA, use single
IAccumGR := 0.0; // DMA, use single
IAccumBR := 0.0; // DMA, use single
for X := 0 to Length(ClusterX) - 1 do
begin
// IWeight := Round(256 * ClusterX[X].Weight); // DMA - do not use anymore
IWeightR:= 256*ClusterX[X].Weight; // DMA, use single, do not round
with LineBufferInt[ClusterX[X].Pos - XMinimum] do
begin
IAccumBR := IAccumBR + B * IWeightR; // DMA
IAccumGR := IAccumGR + G * IWeightR; // DMA
IAccumRR := IAccumRR + R * IWeightR; // DMA
IAccumAR := IAccumAR + A * IWeightR; // DMA
end;
end;
SrcColor.B := ClampInt(round(IAccumBR), 0, $00FF0000) shr 16; // DMA, added round on single
SrcColor.G := ClampInt(round(IAccumGR), 0, $00FF0000) shr 16; // DMA, added round on single
SrcColor.R := ClampInt(round(IAccumRR), 0, $00FF0000) shr 16; // DMA, added round on single
SrcColor.A := ClampInt(round(IAccumAR), 0, $00FF0000) shr 16; // DMA, added round on single
CopyPixel(@SrcColor, DstLine, Info.BytesPerPixel);
Inc(DstLine, Info.BytesPerPixel);
end;
end;
By the way, it seems that the whole problem is in the "optimized" version, the "not optimized one" seems to work well.
Thanks for locating the problem. I probably remove the "optimized" code path altogether, that's not the first problem with it and it's only marginally faster anyway.
Quote from: Galfar on 20 April 2010, 16:06:48
Thanks for locating the problem. I probably remove the "optimized" code path altogether, that's not the first problem with it and it's only marginally faster anyway.
I agree, the difference is very small. That's actually the same what I did in the end.