Author |
Topic  |
|
xequte
    
39053 Posts |
Posted - Nov 11 2015 : 20:08:45
|
function TImageEnProc.AutoCrop(Tolerance: Integer; Background: TRGB; DoCrop: Boolean = True): TRect;
The tolerance value allows you to specify the range of colors that will be matched when performing an automatic crop. So given two color values (e.g. sampled from two corners of an image) how can you calculate the tolerance?
Color1 := ImageEnView1.IEBitmap.Pixels[ 0, 0 ]; // Top-Left
Color2 := ImageEnView1.IEBitmap.Pixels[ 0, ImageEnView1.IEBitmap.Height - 1 ];// Bottom Left
Background.R := ( Color1.R + Color2.R ) div 2; // average R value
RTolerance := abs( Ceil( ( Color1.R - Color2.R ) / 2 )) ;
Tolerance := RTolerance;
Background.G := ( Color1.G + Color2.G ) div 2; // average G value
GTolerance := abs( Ceil( ( Color1.G - Color2.G ) / 2 )) ;
if GTolerance > Tolerance then
Tolerance := GTolerance;
Background.B := ( Color1.B + Color2.B ) div 2; // average B value
BTolerance := abs( Ceil( ( Color1.B - Color2.B ) / 2 )) ;
if BTolerance > Tolerance then
Tolerance := BTolerance;
ImageEnView1.Proc.AutoCrop( Tolerance, Background );
Nigel Xequte Software www.xequte.com nigel@xequte.com
|
|
jrpcguru
  
USA
273 Posts |
Posted - Nov 28 2015 : 15:11:09
|
I have now tried this code on some of the sample images that I sent to you. I had to remove TColor2TRGB because Pixels[0,0] already returned its values as TRGB. My code turned out like this:
function TMainForm.jrGetImageColorAndTolerance(inX1: integer; inY1 : integer; inX2 : integer; inY2 : integer;
out outTolerance : integer) : TRGB;
var
Color1, Color2 : TRGB;
Background : TRGB;
Tolerance, RTolerance, GTolerance, BTolerance : integer;
begin
Color1 := ( ImageEnView1.IEBitmap.Pixels[ inX1, inY1 ]); // first point
Color2 := ( ImageEnView1.IEBitmap.Pixels[ inX2, inY2 ]);// second point
Background.R := ( Color1.R + Color2.R ) div 2; // average R value
RTolerance := abs( Ceil( ( Color1.R - Color2.R ) / 2 )) ;
Tolerance := RTolerance;
Background.G := ( Color1.G + Color2.G ) div 2; // average G value
GTolerance := abs( Ceil( ( Color1.G - Color2.G ) / 2 )) ;
if GTolerance > Tolerance then
Tolerance := GTolerance;
Background.B := ( Color1.B + Color2.B ) div 2; // average B value
BTolerance := abs( Ceil( ( Color1.B - Color2.B ) / 2 )) ;
if BTolerance > Tolerance then
Tolerance := BTolerance;
outTolerance := Tolerance;
result := Background;
end;
I call this code with: ColorBackground := jrGetImageColorAndTolerance(0,0,0,ImageEnView1.IEBitmap.Height - 1,iAutoCropTolerance); ImageEnView1.Proc.AutoCrop(iAutoCropTolerance ,ColorBackground,true);
The tolerance returns as 3 and no autocropping happens. My original code measured the color at 0,0 and through trial and error I found that a tolerance of 110 resulted in a successful autocrop. Though it over crops if the document is too close in color to the platen color.
I'm going to try measuring the color and variation of the platen, but I suspect I will need to wait for your new autocrop algorithm.
J.R. |
 |
|
jrpcguru
  
USA
273 Posts |
Posted - Nov 29 2015 : 10:58:23
|
I have tried calculating the color and tolerance for the entire platen color of my flatbed scanner, then used those values to autocrop images that were scanned on my scanner, the samples that I sent you. My code looks like this:
function TMainForm.jrGetOverallImageColorAndTolerance(out outTolerance : integer) : TColor;
var
Color1, Color2 : TRGB;
tColorPixel, tColorPixelLow, tColorPixelHigh : tColor;
Background : TRGB;
Tolerance, RTolerance, GTolerance, BTolerance : integer;
x,y : integer;
begin
for x := 0 to ImageEnView1.IEBitmap.Width - 1 do
begin
for y := 0 to ImageEnView1.IEBitmap.Height - 1 do
begin
tColorPixel := ImageEnView1.IEBitmap.IECanvas.GDICanvas.Pixels[x,y];
if tColorPixel > tColorPixelHigh then
tColorPixelHigh := tColorPixel;
if tColorPixel < tColorPixelLow then
tColorPixelLow := tColorPixel;
end;
end;
// Color1 := ( ImageEnView1.IEBitmap.Pixels[ x, y ]); // first point
// Color2 := ( ImageEnView1.IEBitmap.Pixels[ x, y ]);// second point
Color1 := TColor2TRGB(tColorPixelLow);
Color2 := TColor2TRGB(tColorPixelHigh);
Background.R := ( Color1.R + Color2.R ) div 2; // average R value
RTolerance := abs( Ceil( ( Color1.R - Color2.R ) / 2 )) ;
Tolerance := RTolerance;
Background.G := ( Color1.G + Color2.G ) div 2; // average G value
GTolerance := abs( Ceil( ( Color1.G - Color2.G ) / 2 )) ;
if GTolerance > Tolerance then
Tolerance := GTolerance;
Background.B := ( Color1.B + Color2.B ) div 2; // average B value
BTolerance := abs( Ceil( ( Color1.B - Color2.B ) / 2 )) ;
if BTolerance > Tolerance then
Tolerance := BTolerance;
outTolerance := Tolerance;
result := TRGB2TColor(Background);
end;
I then use the following to get the values and store them for use during autocropping: BorderColor := jrGetOverallImageColorAndTolerance(iScannerCropTolerance);
And I perform the autocrop like this: ImageEnView1.Proc.AutoCrop(iScannerCropTolerance, BorderColor ,true);
I got the following values as a result: Epson flatbed with a bluish tinted platen: ScannerCropTolerance=127 BorderColor=8356261
HP DeskJet F4480 with a more white platen: border = 8355711 Tolerance = 127
This results in most of the images being completely cropped to nothing! I'm hoping there is something I'm messing up but I'm running out of ideas to make AutoCrop work.
J.R. |
 |
|
xequte
    
39053 Posts |
Posted - Nov 29 2015 : 17:28:16
|
Hi JR
The problem with my code example is that it only samples two pixels, which may not be representative of the border area.
The problem with your code is that it samples the entire image including the non-border area so it will just auto-crop the entire image.
So you need to increase your sample size without including any content. Perhaps you can allow a selection to be made then sample that.
Nigel Xequte Software www.xequte.com nigel@xequte.com
|
 |
|
jrpcguru
  
USA
273 Posts |
Posted - Nov 29 2015 : 18:55:01
|
I used my code only to calculate the values in a clean scan of the platen with no document. I rewrote the code to calculate values only for the full left edge, top edge, bottom edge, or right edge. I also fixed a bug that prevented a proper comparison with the low pixel value:
if inEdge = 'L' then
begin
tColorPixel := ImageEnView1.IEBitmap.IECanvas.GDICanvas.Pixels[0,0];
tColorPixelHigh := tColorPixel;
tColorPixelLow := tColorPixel; //initialize to allow proper comparison
for y := 0 to ImageEnView1.IEBitmap.Height - 1 do
begin
tColorPixel := ImageEnView1.IEBitmap.IECanvas.GDICanvas.Pixels[0,y];
if tColorPixel > tColorPixelHigh then
tColorPixelHigh := tColorPixel;
if tColorPixel < tColorPixelLow then
tColorPixelLow := tColorPixel;
end;
end
The original code yielded Epson flatbed ScannerCropTolerance=127 BorderColor=8356261
The bug fix yielded the following values for all the edges: border = 15658730 Tolerance = 17
border = 15526887 Tolerance = 19
border = 15132647 Tolerance = 24
border = 15132645 Tolerance = 24
So correcting the bug gave a much different color value but the tolerance was no where near enough to successfully autocrop.
I also tried RemoveChromaKey with a selection to identify the color of the area to autocrop:
if ImageEnView1.Selected then
begin
// KeyColorRGB := ImageEnView1.Proc.CalcAverageRGB( 100 );
// ImageEnView1.Proc.RemoveChromaKey( KeyColorRGB, 0.21, 30, 2, 2,true );
KeyColorRGB := ImageEnView1.Proc.GuessChromaKeyColor( dbTolerance );
iTolerance := Trunc(dbTolerance * 1000);
CropBox := ImageEnView1.Proc.AutoCrop(iTolerance ,KeyColorRGB,true);
RemoveChromakey did not work since it only affected the selection box. The tolerance for GuessChromaKey is apparently not related to the tolerance for autocrop so that still failed.
I have tried
J.R. |
 |
|
jrpcguru
  
USA
273 Posts |
Posted - Dec 01 2015 : 17:43:37
|
Further information on using AutoCrop:
The revised code that I posted last, does work pretty well at AutoCrop, as long as I use the higher tolerance discovered through trial and error of 110. I'm hoping there is another possible algorithm to calculate the tolerance since it does vary somewhat depending on the color of the platen or other border around the image.
I have been working with AutoCrop2 to see if I can auto crop black borders. I find that using AutoCrop with my own tolerance of 110 or close to that, seems to work pretty well. I've had to guess at the correct tolerance for using Autocrop2. I wonder if there is an algorithm that will calculate that? I also wonder what the limits are for the tolerance used in AutoCrop2? It is a completely different value than with Autocrop. The help defines the limits of the tolerance for Autocrop as 0 to 255, but for Autocrop2 it only says it must be greater than 0. I would like to error trap my code for setting these values. Thanks for your help so far on getting Autocrop to work well.
J.R. |
 |
|
Uwe
  
284 Posts |
Posted - Dec 01 2015 : 18:49:04
|
To make things even more confusing: the tolerance level for Autocrop varies depending on the file format as well. PEF, RWL, CRW and JPG files and their embedded previews require a different tolerance level than those of ARW and RAF files for example.
-Uwe |
 |
|
jrpcguru
  
USA
273 Posts |
Posted - Dec 01 2015 : 19:18:13
|
Wow, things sure can get ugly!
I am scanning to JPG, TIF, or PSD. In most cases I will be autocropping unsaved images in ImageEnView. I do have some older images that I forgot to crop. I hope that helps in determining a better algorithm. In fact that suggests that I need to test the tolerance algorithm with JPG files and with freshly scanned and unsaved images. Too late, tonight. Thanks.
J.R. |
 |
|
|
Topic  |
|
|
|