Extracting data digitally - image-processing

I have 200 copies of this page(15 * 10 matrix) and i have to write all the numbers from 0 - 9 in each corresponding cell and then extract those digits digitally in a seperate image of (32*32 pixels) for each digit, after scanning each page once. How can i achieve this? This is required for my research purpose. I am a CS student so i can code too.
Update:
For mark : Here is one of the scanned image
This is for some local language ( 0 - 9) ..
Update 2:
The commands for the previous image are working fine but on new images,something is getting wrong(some kind of offsets)..
I am attaching the image below
What changes do u suggest ?

Updated Answer
I have taken your feedback and improved the algorithm to the following bash script now...
#!/bin/bash
################################################################################
# dice
#
# Trim borders off an image (twice) and then dice into 10x15 cells.
#
# Usage: ./dice image
################################################################################
# Pick up image name from first parameter
image="$1"
echo DEBUG: Processing image $image...
# Apply median filter to remove noisy black dots around image and then get the
# dimensions of the "trim box" - note we don't use the (degraded) median-filtered image in
# later steps.
trimbox=$(convert "$image" -median 9x9 -fuzz 50% -format %# info:)
echo DEBUG: trimbox $trimbox
# Now trim original unfiltered image into stage1-$$.png (for debug)
convert "$1" -crop $trimbox +repage stage1-$$.png
echo DEBUG: Trimmed outer: stage1-$$.png
# Now trim column headings
convert stage1-$$.png -crop 2000x2590+120+190 +repage stage2-$$.png
echo DEBUG: Trimmed inner: stage2-$$.png
# Now slice into 10x15 rectangles
echo DEBUG: Slicing and dicing
convert stage2-$$.png -crop 10x15# +repage rectangles-%03d.png
# Now trim the edges off the rectangles and resize all to a constant size
for f in rectangles*png; do
echo DEBUG: Trimming and resizing $f
trimbox=$(convert "$f" -median 9x9 -shave 15x15 -bordercolor black -border 15 -threshold 50% -floodfill +0+0 white -fuzz 50% -format %# info:)
echo DEBUG: Cell trimbox $trimbox
convert "$f" -crop $trimbox +repage -resize 32x32! "$f"
done
Here are the resulting cells - i.e. 150 separate image files. I have put a red border around the individual cells/files so you can see their extent:
Original Answer
I would do that with ImageMagick which is free and installed on most Linux distros and is available for OSX and Windows too. There are Perl, PHP, Java, node, .NET, Ruby, C/C++ bindings too if you prefer those languages. Here I am using the command line in Terminal.
First job is to get rid of noise and trim the outer edges:
convert scan.jpg -median 3x3 -fuzz 50% -trim +repage trimmed1.png
Now, trim again to get rid of outer frame and column titles across the top:
convert trimmed1.png -crop 2000x2590+120+190 +repage trimmed2.png
Now divide into 10 cells by 15 cells and save as rectangles-nnn.png
convert trimmed2.png -crop 10x15# rectangles-%03d.png
Check what we got - yes, 150 images:
ls -l rect*
rectangles-000.png rectangles-022.png rectangles-044.png rectangles-066.png rectangles-088.png rectangles-110.png rectangles-132.png
rectangles-001.png rectangles-023.png rectangles-045.png rectangles-067.png rectangles-089.png rectangles-111.png rectangles-133.png
rectangles-002.png rectangles-024.png rectangles-046.png rectangles-068.png rectangles-090.png rectangles-112.png rectangles-134.png
rectangles-003.png rectangles-025.png rectangles-047.png rectangles-069.png rectangles-091.png rectangles-113.png rectangles-135.png
rectangles-004.png rectangles-026.png rectangles-048.png rectangles-070.png rectangles-092.png rectangles-114.png rectangles-136.png
rectangles-005.png rectangles-027.png rectangles-049.png rectangles-071.png rectangles-093.png rectangles-115.png rectangles-137.png
rectangles-006.png rectangles-028.png rectangles-050.png rectangles-072.png rectangles-094.png rectangles-116.png rectangles-138.png
rectangles-007.png rectangles-029.png rectangles-051.png rectangles-073.png rectangles-095.png rectangles-117.png rectangles-139.png
rectangles-008.png rectangles-030.png rectangles-052.png rectangles-074.png rectangles-096.png rectangles-118.png rectangles-140.png
rectangles-009.png rectangles-031.png rectangles-053.png rectangles-075.png rectangles-097.png rectangles-119.png rectangles-141.png
rectangles-010.png rectangles-032.png rectangles-054.png rectangles-076.png rectangles-098.png rectangles-120.png rectangles-142.png
rectangles-011.png rectangles-033.png rectangles-055.png rectangles-077.png rectangles-099.png rectangles-121.png rectangles-143.png
rectangles-012.png rectangles-034.png rectangles-056.png rectangles-078.png rectangles-100.png rectangles-122.png rectangles-144.png
rectangles-013.png rectangles-035.png rectangles-057.png rectangles-079.png rectangles-101.png rectangles-123.png rectangles-145.png
rectangles-014.png rectangles-036.png rectangles-058.png rectangles-080.png rectangles-102.png rectangles-124.png rectangles-146.png
rectangles-015.png rectangles-037.png rectangles-059.png rectangles-081.png rectangles-103.png rectangles-125.png rectangles-147.png
rectangles-016.png rectangles-038.png rectangles-060.png rectangles-082.png rectangles-104.png rectangles-126.png rectangles-148.png
rectangles-017.png rectangles-039.png rectangles-061.png rectangles-083.png rectangles-105.png rectangles-127.png rectangles-149.png
rectangles-018.png rectangles-040.png rectangles-062.png rectangles-084.png rectangles-106.png rectangles-128.png
rectangles-019.png rectangles-041.png rectangles-063.png rectangles-085.png rectangles-107.png rectangles-129.png
rectangles-020.png rectangles-042.png rectangles-064.png rectangles-086.png rectangles-108.png rectangles-130.png
rectangles-021.png rectangles-043.png rectangles-065.png rectangles-087.png rectangles-109.png rectangles-131.png
Look at first couple:
You can do those 3 steps in 1 like this:
convert scan.jpg -median 3x3 -fuzz 50% -trim +repage \
-crop 2000x2590+120+190 +repage \
-crop 10x15# rectangles-%03d.png
You may want to shave a few pixels off each side of each image and resize to 32x32 with something like (untested):
mogrify -shave 3x3 -resize 32x32! rectangles*png

Related

Imagemagick convert gif creation random image order

i have a folder of images with names foo<bar>.png where <bar> ranges from 0 to 100.
When i create a gif of these images with
convert -dispose previous -delay 10 -resize 25% -loop 0 *.png myimage.gif
it creates a gif with images in order like 0,1,2,3...
Is there a command to select images in random order?
If your PNG images are all the same dimensions, and if the number of images can be evenly divided into a grid, like 72 images would make a grid of 8 x 9 images, and if your images are small enough to read them all into a single ImageMagick command, here is a command that will randomize the order of a group of 72 input images...
convert *.png -virtual-pixel tile +append -crop 9x1# -append +repage ^
-crop 1x9# -distort affine "0,0 %[fx:floor(rand()*8)*(w/8)],0" -append +repage ^
-crop 8x1# -distort affine "0,0 0,%[fx:floor(rand()*9)*(h/9)]" +append +repage ^
-crop 8x9# +repage -set delay 10 -loop 0 image.gif
It basically makes a grid, randomly rolls all the rows, then randomly rolls all the columns. The shuffle scatters the images pretty well, but if you want a deeper shuffle, copy and paste those two "-crop ... -distort" lines, and add them below the first two...
convert *.png -virtual-pixel tile +append -crop 9x1# -append +repage ^
-crop 1x9# -distort affine "0,0 %[fx:floor(rand()*8)*(w/8)],0" -append +repage ^
-crop 8x1# -distort affine "0,0 0,%[fx:floor(rand()*9)*(h/9)]" +append +repage ^
-crop 1x9# -distort affine "0,0 %[fx:floor(rand()*8)*(w/8)],0" -append +repage ^
-crop 8x1# -distort affine "0,0 0,%[fx:floor(rand()*9)*(h/9)]" +append +repage ^
-crop 8x9# +repage -set delay 10 -loop 0 image.gif
Carefully replace the "8"s and "9"s with the width and height of the grid that holds the number of images you're using. I use it in a script that shuffles a deck of playing card images, 13 rows and 4 columns.
This uses ImageMagick v6 in Windows CMD syntax. In a BAT script double all the percent signs "%%". It would probably work on a *nix OS by changing all the continued-line carets "^" to backslashes "\". For ImageMagick v7 use "magick" instead of "convert".
I can tell you 2/3 of the answer on Windows, and hopefully some other kind soul can add the rest for you. Nobody said answers have to be complete.
Create a text file containing the names of the PNGs you want to animate. I believe that is:
DIR /B *.png > filelist.txt
Shuffle the lines in that file. I don't know how to do that in Windows. In Linux and macOS it is shuf. Here's a little Python equivalent:
python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," filelist.txt > shuffled.txt
Pass that file to ImageMagick like this:
convert -loop 0 -delay 80 #filelist.txt animation.gif
If you get that working, you can avoid the need for a temporary file by using this syntax:
DIR /B *.png | SHUFFLELINES | convert -loop 0 -delay 80 #- animation.gif

Imagemagick convert to name tiles as row/column doesn't work as expected with -extent

I have an image, 5120  ×  4352 that I crop into 2048x2048 tiles. I want to name my cropped tiles like
tile_0_0.png
tile_0_1.png
tile_0_2.png
tile_1_0.png
tile_1_1.png
tile_1_2.png
...
But this command:
convert image.png -crop 2048x2048 -gravity northwest \
-extent 2048x2048 -transparent white \
-set 'filename:tile' '%[fx:page.x/2048]_%[fx:page.y/2048]' \
+repage +adjoin 'tile_%[filename:tile].png'
Gives me this result:
tile_0_0.png
tile_0_1.png
tile_0_16.png
tile_1_0.png
tile_1_1.png
tile_1_16.png
tile_4_0.png
tile_4_1.png
tile_4_16.png
I suspect it has do with the tiles on the last row and column aren't fully 2048x2048, but the extent command makes the end result still 2048, but how can I use this with tiles and file names?
My current workaround is to first resize the original image like this, and then run the above command:
convert image.png -gravity northwest \
-extent 2048x2048 -transparent white bigger.png
But it would be nice to do it in one swoop :)
Using ImageMagick you could set a viewport that is just enough larger than the input image so it divides evenly by 2048. Then a no-op distort will enlarge the viewport to that size. That way the "-crop 2048x2048" will create pieces that are already 2048 square.
Here's a sample command I worked up in Windows, and I'm pretty sure I translated it to work correctly as a *nix command.
convert image.png \
-set option:distort:viewport '%[fx:w-(w%2048)+2048]x%[fx:h-(h%2048)+2048]' \
-virtual-pixel none -distort SRT 0 +repage -crop 2048x2048 \
-set 'filename:tile' '%[fx:page.x/2048]_%[fx:page.y/2048]' \
+repage +adjoin 'tile_%[filename:tile].png'
The "-distort SRT" operation does nothing except expand the viewport to dimensions that divide evenly by 2048, with a result just like doing an "-extent" before the crop. And "-virtual-pixel none" will leave a transparent background in the overflow areas.
Edited to add: The formula for extending the viewport in the above command will incorrectly add another 2048 pixels even if the dimension is already divisible by 2048. It also gives an incorrect result if the dimension is less than 2048. Consider using a formula like this for setting the viewport to handle those conditions...
'%[fx:w+(w%2048?2048-w%2048:0)]x%[fx:h+(h%2048?2048-h%2048:0)]'

Multiple resize operations in ImageMagick

I'm trying to combine some operations using ImageMagick's magick CLI, specifically two operations that resize/scale the image, a random one that does -resize and a bunch of other stuff, plus the answer from this question (Average image color excluding transparency with Imagemagick).
The naive "mix everything together" doesn't work:
magick image -resize 10x10 ... -scale 1x1! -alpha off -format "%[pixel:u.p]\n" info:
...as I get an answer of "black", because this is obviously ignoring my image and using a blank image instead.
I've also tried with subimages (using \( ... \)) but that has the same problem
The following command works fine for me on ImageMagick 6.9.10.16 Q16. What is your ImageMagick version and what other commands do you need in the command line. You only show ...! What else is there? Also can you post your image? You cannot just put "image" in your command line. You have to specify the actual image file and possibly the path to it.
Input:
convert logo.png -transparent white -resize 50% -scale 1x1! -alpha off -format "%[pixel:u.p]" info:
srgb(100,82,99)
Same with IM 7.0.8.16 Q16 HDRI:
magick logo.png -transparent white -resize 50% -scale 1x1! -alpha off -format "%[pixel:u.p]" info:
srgb(100,81,99)
The slight difference is likely a difference from precision with IM 6 (non-hdri) and IM 7 (with hydra).

Autotrim white border from scanned image with ImageMagick?

I have ~200 scanned photos which I want to crop the white space out of. See example:
Can someone provide me with the appropriate command line code to do this?... I have been trying to sort out the -trim and -fuzz options with no luck. NOT ALL images are same size (i.e. 4x6, 5x7, etc). All images were scanned/saved as jpg
Ideal scenario is a script where new trimmed photos are saved in one subdirectory.
Thanks in advance!
I would suggest using -morphology to remove the scan artifacts, trim, and then capture the resulting paging.
PAGE_OFFSET=$(convert TrmkF.jpg -morphology Dilate:3 Diamond:3,5 -fuzz 10% -trim -format '%wx%h%O' info:-)
The $PAGE_OFFSET variable should now have the rough location of the scanned photo. We can apply that value with the -crop command.
convert TrmkF.jpg -crop $PAGE_OFFSET output.jpg
[![output][1]][1]
Edit
A (powershell) batch script may look as simple as...
Get-ChildItem "C:\path\to\photos" -Filter *.jpg |
Foreach-Object {
$pageOffset = magick $_.FullName -morphology Dilate:3 Diamond:3,5 -fuzz 10% -trim -format '%xx%h%O' info:- | Out-String
$output = $_.FullName + ".output.jpg"
magick $_.FullName -crop $pageOffset +repage $output
}
ymmv
[1]: https://i.stack.imgur.com/u8bSs.png
I've found that the above gives bad results, I think the formatting is different on MacOS or something so sharing the success story here. I have exactly this same issue - hundreds of scanned photos with some blotches in the white ruining the auto trim function.
I just modified parameters from the other individual's answer and got amazing results using this:
cd into your folder of images
mkdir ../done
v
echo "$f";\
size=$(magick "$f" -bordercolor White -border 10x10 \
-morphology Dilate:5 Diamond:5,7 -fuzz 5% -trim \
-format "%wx%h%O" info:-); \
echo $size; \
magick "$f" -bordercolor White -border 10x10 -crop $size +repage "../done/$f"; done;

Adding padding to an image with imagemagick ONLY if white or transparent background

Im working on an image gallery application and we need to conditionally add padding around images that have a white or transparent background so they look normal inside the grid on our page.
Basically we need to:
Check to see if the image has a white or transparent background
If yes, add a 5px transparent border around the image.
If no, do nothing.
Is there a way to do this with ImageMagick in one or two lines or do we need to use an additional library?
Something along these lines probably sums up all the stuff that follows:
#!/bin/bash
# By default, do not add border
addborder=0
# Get image geometry to see if IM thinks it has a border
geometry=$(identify -format "%g" "$1")
echo DEBUG: geometry: $geometry
# Ask IM what would happen if we trimmed image
trim=$(convert "$1" -format "%#" info:)
echo DEBUG: trim: $trim
if [ $geometry = $trim ]; then
echo DEBUG: Image does not have a border
exit
fi
# Get top-left pixel
topleft=$(convert "$1" -format "%[pixel:s.p{0,0}]" info:)
echo DEBUG: Image has border, border colour is: $topleft
# Decide whether to add border
[ $topleft = "white" ] && addborder=1
[ $topleft = "gray(255)" ] && addborder=1
[ $topleft = "graya(0,0)" ] && addborder=1
[ $topleft = "none" ] && addborder=1
echo DEBUG:addborder: $addborder
if [ $addborder -eq 1 ]; then
echo DEBUG: adding border
convert "$1" -bordercolor none -border 5x5 output.png
fi
Other related information and ideas...
You can just use Imageagick's trim function to trim any solid or transparent border, like this:
convert input.jpg -trim +repage output.jpg
If there is no solid border it does nothing. The +repage resets the canvas around the picture so it no longer remembers it was part of something bigger.
Or, you can do a whole directory full of images with mogrify
mogrify -fuzz 15% -trim +repage *.jpg
The fuzz factor allows there to be slight variations in the border colour whilst still trimming it.
Adding the new border on can be done at the same time with this:
convert input.jpg -fuzz 10% -trim +repage -bordercolor white -border 5x5 output.jpg
Or, if you want to do some more detailed processing, you could get the top-left corner pixel and decide what you want to do dependent on its value:
convert input.png -format "%[pixel:s.p{0,0}]" info:
Let's create a transparent image and check what we get:
convert -size 10x10 xc:none input.png
convert input.png -format "%[pixel:s.p{0,0}]" info:
graya(0,0)
and a white one:
convert -size 10x10 xc:white input.png
convert input.png -format "%[pixel:s.p{0,0}]" info:
gray(255)
and a red one:
convert -size 10x10 xc:red input.png
convert input.png -format "%[pixel:s.p{0,0}]" info:
red

Resources