Page 1 of 1

Analyze a line of pixels.

Posted: 2018-11-25T14:03:58-07:00
by pr3sidentspence
Hi,

I'm not sure if IM can do this, but it can do a lot, so I'd thought I'd ask.

We're involved in a large historical postcard digitization project. Waiting for the scanner to scan is a significant portion of the workflow so we currently scan three cards at a time. Typically, the three cards will be roughly the same size and each takes roughly the same portion of the scanning bed surface. In this case, it's simple to use IM to chop the scans into the top, middle, and bottom cards along predefined chop lines between the cards.

Sometimes, though, the cards are larger and only two, or even one can be scanned at a time. I've been considering creating a chop-line finder script. The first step was to create smaller working copies of the roughly 5000x7000, raw, color bitmaps. Resizing them to about 200x280 seems like it should have enough information to find the gaps between cards. Then I cropped a 1x280 line right down the center of the image. I now have a line of pixels through which I can look for segments that are the value of our scanning background (roughly IM's gray(56)).

After becoming thoroughly fed up with working with batch files, I'm going to tackle this in PowerShell scripts.

My question is, do I need to figure out how to...
- read the bitmap pixel values from the hex in the .BMP files into an array
- figure out a method for detecting the gray sections
...or can IM just do one, or both of those tasks for me?
I suspect there might be something in those "fx" options that might do.

Thanks.

Re: Analyze a line of pixels.

Posted: 2018-11-25T14:18:43-07:00
by snibgo
Unless you show an example, we need to ask more questions or make assumptions.

Your background is roughly gray(56), but what is the foreground? Darker or lighter or could be both?

There needs to be something visual that distinguishes foreground from background. If that's a simple threshold, then connected components can give the bounding rectangles of each postcard.

Re: Analyze a line of pixels.

Posted: 2018-11-25T14:22:12-07:00
by fmw42
If you can use Windows 10 unix or Windows with Cygwin, you can try my script, multicrop2, at my link below.

Alternately, threshold or floodfill the image into white on black background and use -connected-components to get the bounding boxes and then crop your original with the bounding box values. See https://imagemagick.org/script/connected-components.php

Re: Analyze a line of pixels.

Posted: 2018-11-25T14:26:13-07:00
by fmw42
Let's say that your images are aligned vertically. You can just average the images to one column, then perhaps threshold it, then convert to text with txt: format, then analyze the text for gaps.

Re: Analyze a line of pixels.

Posted: 2018-11-25T14:26:27-07:00
by pr3sidentspence
https://1drv.ms/u/s!As3ZytCDCPbLjvl-giXs0-tWJuq2bQ


Image

The scratches on the scanner glass won't be present in future scans. The color of the background can and will be present in the postcards themselves, which could cause false positives in my detection process, but my plan was to do 3-10 of these tests, at various X values, and if they agreed on Y chop lines, run with it.

Re: Analyze a line of pixels.

Posted: 2018-11-25T19:10:57-07:00
by pr3sidentspence
Thanks to you both for your advice.

Fred, I was looking at your multicrop and multicrop2 before and meant to ask you what the difference between them was. I had tried them both on this a week or two, but I might not have been using it correctly. I will try again though, I understand things a bit better now.

I like your averaging idea! And I never would have thought of converting to text.

Re: Analyze a line of pixels.

Posted: 2018-11-25T20:03:37-07:00
by fmw42
The main difference is that multicrop uses a grid search, whereas multicrop2 searches every pixels.

I am not having much luck with your image with multicrop2, possible due to the white curved lines in the background.

Re: Analyze a line of pixels.

Posted: 2018-11-25T22:02:53-07:00
by pr3sidentspence
That might be why I had trouble before, too. Those are scratches on the scanner glass. We won't be using that scanner going forward (although, they did make nice guides for the technician :) ).

I did a -resize 1x300! and then converted to text, the gray strips are pretty obvious:

# ImageMagick pixel enumeration: 1,300,65535,srgb
0,0: (14392,14392,13878) #383836 srgb(56,56,54)
0,1: (14392,14649,14135) #383937 srgb(56,57,55)
0,2: (14392,14649,14135) #383937 srgb(56,57,55)
0,3: (14392,14649,14135) #383937 srgb(56,57,55)
0,4: (14392,14649,14135) #383937 srgb(56,57,55)
0,5: (14392,14649,14135) #383937 srgb(56,57,55)
0,6: (14392,14649,14135) #383937 srgb(56,57,55)
0,7: (14392,14392,13878) #383836 srgb(56,56,54)
0,8: (14392,14649,14135) #383937 srgb(56,57,55)
0,9: (14392,14649,14135) #383937 srgb(56,57,55)
0,10: (14392,14649,14135) #383937 srgb(56,57,55)
0,11: (14392,14649,14135) #383937 srgb(56,57,55)
0,12: (14649,14649,14135) #393937 srgb(57,57,55)
0,13: (14649,14649,14135) #393937 srgb(57,57,55)

0,14: (14649,14649,14135) #393937 srgb(57,57,55)
0,15: (35723,34438,30326) #8B8676 srgb(139,134,118)
0,16: (44975,43176,38036) #AFA894 srgb(175,168,148)
0,17: (43690,42148,37008) #AAA490 srgb(170,164,144)
0,18: (43947,42405,37265) #ABA591 srgb(171,165,145)
0,19: (44204,42662,37522) #ACA692 srgb(172,166,146)
0,20: (44204,42662,37522) #ACA692 srgb(172,166,146)
0,21: (44204,42662,37522) #ACA692 srgb(172,166,146)
0,22: (44461,42919,37779) #ADA793 srgb(173,167,147)
0,23: (44461,42919,37779) #ADA793 srgb(173,167,147)
0,24: (44461,42919,37779) #ADA793 srgb(173,167,147)
0,25: (44461,42919,37779) #ADA793 srgb(173,167,147)
0,26: (44461,42919,37779) #ADA793 srgb(173,167,147)

[...]

0,92: (23644,23130,19789) #5C5A4D srgb(92,90,77)
0,93: (22873,22616,19018) #59584A srgb(89,88,74)
0,94: (22616,22102,18761) #585649 srgb(88,86,73)
0,95: (22102,21845,18247) #565547 srgb(86,85,71)
0,96: (22873,22359,18761) #595749 srgb(89,87,73)
0,97: (23644,23130,19275) #5C5A4B srgb(92,90,75)
0,98: (26471,25700,21588) #676454 srgb(103,100,84)
0,99: (25957,25186,21588) #656254 srgb(101,98,84)
0,100: (15420,15420,14649) #3C3C39 srgb(60,60,57)
0,101: (13878,14135,13878) #363736 srgb(54,55,54)
0,102: (14392,14392,14135) #383837 srgb(56,56,55)
0,103: (14392,14649,14135) #383937 srgb(56,57,55)
0,104: (14649,14649,14135) #393937 srgb(57,57,55)
0,105: (13878,14135,13878) #363736 srgb(54,55,54)

0,106: (16962,16962,15677) #42423D srgb(66,66,61)
0,107: (34181,32639,27756) #857F6C srgb(133,127,108)
0,108: (38293,36494,31097) #958E79 srgb(149,142,121)
0,109: (38036,36237,31097) #948D79 srgb(148,141,121)
0,110: (38293,36494,31097) #958E79 srgb(149,142,121)
0,111: (38807,36751,31611) #978F7B srgb(151,143,123)
0,112: (39064,37265,31611) #98917B srgb(152,145,123)

[...]

0,187: (22616,23387,21331) #585B53 srgb(88,91,83)
0,188: (23130,23901,21845) #5A5D55 srgb(90,93,85)
0,189: (20303,21331,19789) #4F534D srgb(79,83,77)
0,190: (21845,22873,20817) #555951 srgb(85,89,81)
0,191: (24929,25957,23387) #61655B srgb(97,101,91)
0,192: (27756,28527,25443) #6C6F63 srgb(108,111,99)
0,193: (28270,28784,25700) #6E7064 srgb(110,112,100)
0,194: (29555,30069,26471) #737567 srgb(115,117,103)
0,195: (35209,34181,29555) #898573 srgb(137,133,115)
0,196: (26985,25700,22616) #696458 srgb(105,100,88)
0,197: (13878,13878,13621) #363635 srgb(54,54,53)
0,198: (14392,14649,14135) #383937 srgb(56,57,55)
0,199: (14392,14649,14135) #383937 srgb(56,57,55)
0,200: (14649,14906,14392) #393A38 srgb(57,58,56)
0,201: (14649,14906,14392) #393A38 srgb(57,58,56)
0,202: (14135,14392,13878) #373836 srgb(55,56,54)

0,203: (22102,22102,20046) #56564E srgb(86,86,78)
0,204: (35466,34438,30583) #8A8677 srgb(138,134,119)
0,205: (37779,36494,32382) #938E7E srgb(147,142,126)
0,206: (37779,36494,32382) #938E7E srgb(147,142,126)
0,207: (37522,36237,32125) #928D7D srgb(146,141,125)
0,208: (37008,35723,31868) #908B7C srgb(144,139,124)
0,209: (38550,37008,33153) #969081 srgb(150,144,129)
0,210: (39578,37779,33667) #9A9383 srgb(154,147,131)

[...]

0,286: (39835,38807,35980) #9B978C srgb(155,151,140)
0,287: (39578,38550,35723) #9A968B srgb(154,150,139)
0,288: (43176,41634,38550) #A8A296 srgb(168,162,150)
0,289: (43947,42405,39064) #ABA598 srgb(171,165,152)
0,290: (43690,42148,38550) #AAA496 srgb(170,164,150)
0,291: (43433,41634,37779) #A9A293 srgb(169,162,147)
0,292: (42405,40349,36237) #A59D8D srgb(165,157,141)
0,293: (31868,30583,27242) #7C776A srgb(124,119,106)
0,294: (15420,15677,14906) #3C3D3A srgb(60,61,58)
0,295: (13621,14135,13878) #353736 srgb(53,55,54)
0,296: (13878,14392,14135) #363837 srgb(54,56,55)
0,297: (13878,14392,14135) #363837 srgb(54,56,55)

0,298: (13878,14392,14135) #363837 srgb(54,56,55)
0,299: (13878,14392,14135) #363837 srgb(54,56,55)

I think finding the gaps will be pretty easy with this info. Thank you again!

Re: Analyze a line of pixels.

Posted: 2018-11-26T00:38:03-07:00
by muccigrosso
It looks like the gray might work, but since the images appear to be basically grayscale, why not use a highly colored background, like a bright red piece of paper? Finding the gaps with that should be easier.

Re: Analyze a line of pixels.

Posted: 2018-11-26T07:13:23-07:00
by snibgo
My page Subimage rectangles gives some Windows BAT scripts for this.

Another possibility is to calculate the standard deviation of each row. This is 0.0 (every pixel is the same) to 0.5 (the pixels are massively different). For example:

Code: Select all

magick 1f.bmp -resize 10% -crop x1 +repage -format "%[fx:standard_deviation]\n" info:
The start of the output is:

Code: Select all

0.00802247
0.00673682
0.00753214
0.00756676
0.00776039
0.00750348
0.00750133
0.0075658
0.00744472
0.00769346
0.00736978
0.00789681
0.00773879
0.00750508
0.00741142
0.00796257
0.00794099
0.00717635
0.00768031
0.00759453
0.00797671
0.00812716
0.00862419
0.00929651
0.00852029
0.00878292
0.0097658
0.00951415
0.00909568
0.00924274
0.0100329
0.00954755
0.00997917
0.0162756
0.0660225
0.229288
0.261704
0.277685
0.27406
0.27604
0.275941
{etc}
It is clear where the first postcard starts. This works with any colour background, provided it is a reasonably constant colour.

Re: Analyze a line of pixels.

Posted: 2018-11-26T11:33:23-07:00
by pr3sidentspence
@snibgo Oh, I like that.

@muccigrosso The primary reason is that we need to include a bit of the gray background in our published images. Another issue is that some of the cards are color artwork.

Re: Analyze a line of pixels.

Posted: 2018-11-26T11:48:42-07:00
by pr3sidentspence
@snibgo What is it about the command you provided that makes it iterate over all the rows? When I read it, it looks to me like it will just get the top row. Obviously, it doesn't just do that, but what about the command makes it do every row in the resized image?

Re: Analyze a line of pixels.

Posted: 2018-11-26T12:44:12-07:00
by snibgo
magick <-- start magick
1f.bmp <-- read your image
-resize 10% <-- resize to 10% linearly, which saves 99% of processing
-crop x1 +repage <-- chop into rows, so we have now one image per input row. "+repage" removes the canvas metadata from each image, which we don't need to do, but it's a good habit.
-format "%[fx:standard_deviation]\n" <-- We will write this text for every image (ie every input row). "\n" gives a new line. The "fx:" expression could be more complex.
info: <-- Write the formatted text.

It takes about 20 seconds on my laptop. Without the resize it would take around 2000 seconds.

When you have found the postcard boundaries, you need to multiply the found line numbers by 10, because we resized by 1/10.

This gives you the approximate boundaries. If you need greater precision, you can crop the input to the first boundary plus or minus 10 rows, then repeat the command on that crop, without the resize.

EDIT: Perhaps I should add that "-crop x1+0+0" would give just the first row, but omitting the offsets breaks it into tiles, in this case one tile per row. See http://www.imagemagick.org/script/comma ... s.php#crop

Re: Analyze a line of pixels.

Posted: 2018-11-26T15:46:06-07:00
by pr3sidentspence
Your edit is what I was missing. Thank you very much!

Re: Analyze a line of pixels.

Posted: 2018-11-30T08:05:53-07:00
by pr3sidentspence
If anyone is interested, my mostly complete powershell script is at https://pr3sidentspence.github.io/ called findDocsInScanAndSeparate.ps1