ImageMagick split image by background color - imagemagick
I have big image https://buildyourboard.pro/userboards/board-img/data/clipart.png
how can I segmentate this image to small images by transparent (or another) background?
Images not in grid, so code should find position of every pic in image
If you run this command, it will scrunch all the pixels up into an image that is just one pixel wide and has the original height of your image. You will then see that all lines that have the word none correspond to all the locations where you can draw a horizontal line across the image without intersecting with any of your board backgrounds:
convert boards.png -resize 1x! txt: | more
# ImageMagick pixel enumeration: 1,4667,255,srgba
0,0: (0,0,0,0) #00000000 none
0,1: (0,0,0,0) #00000000 none
0,2: (0,0,0,0) #00000000 none
...
...
...
0,547: (0,0,0,0) #00000000 none
0,548: (0,0,0,0) #00000000 none
0,549: (0,0,0,0) #00000000 none
0,550: (0,0,0,0) #00000000 none
0,551: (0,0,0,0) #00000000 none
0,552: (0,0,0,0) #00000000 none
0,553: (0,0,0,0) #00000000 none
0,554: (0,0,0,0) #00000000 none
0,555: (39038,36633,35446,0) #988F8A00 srgba(152,143,138,0)
0,556: (38889,36248,34984,12) #978D8800 srgba(151,141,136,0.000183108)
0,557: (38348,35253,33873,75) #95898400 srgba(149,137,132,0.00114443)
0,558: (35061,31775,30664,98) #887C7700 srgba(136,124,119,0.00149538)
0,559: (33894,30508,29428,164) #84777301 srgba(132,119,115,0.00250248)
0,560: (34379,30968,29853,243) #86787401 srgba(134,120,116,0.00370794)
Now you can see that the first place where it goes from there being nothing in a horizontal line to there being something is at line 555. So basically, you want to detect where it changes from none to something.
That is readily done through awk like this:
convert boards.png -resize 1x! txt: | awk 'inside && /none/{inside=0;print;next} !inside && ! /none/{inside=1;print}'
# ImageMagick pixel enumeration: 1,4667,255,srgba
0,0: (0,0,0,0) #00000000 none
0,555: (39038,36633,35446,0) #988F8A00 srgba(152,143,138,0)
0,911: (0,0,0,0) #00000000 none
0,1082: (36701,34188,35001,0) #8F858800 srgba(143,133,136,0)
0,1433: (0,0,0,0) #00000000 none
0,1570: (33489,32153,32838,4) #827D8000 srgba(130,125,128,6.10361e-05)
0,1937: (0,0,0,0) #00000000 none
0,2135: (29884,28945,29339,4) #74717200 srgba(116,113,114,6.10361e-05)
0,2486: (0,0,0,0) #00000000 none
0,2621: (28668,27300,25241,5) #706A6200 srgba(112,106,98,7.62951e-05)
0,2972: (0,0,0,0) #00000000 none
0,3216: (35066,32529,28581,2) #887F6F00 srgba(136,127,111,3.0518e-05)
0,3612: (0,0,0,0) #00000000 none
So, now we know we can make horizontal cuts across the picture at lines 555, 911, 1082, 1433 etc.
I will draw the first 3 such lines in like this:
convert boards.png -stroke red -draw "line 0,555 12000,555" -draw "line 0,911 12000,911" -draw "line 0,1082 12000,1082" result.jpg
Now, you cut along those lines - like this:
convert boards.png -crop x911+0+0 row1.jpg
convert boards.png -crop x416+911+1082 row2.jpg
Then apply exactly the same procedure in the vertical direction, replacing -resize 1x! with -resize x1!.
Related
Find colored box in image and create a mask file
I would like to create a hotfolder for my motion camera, into which I can drop images marking areas, which should be excluded in motion recognition via a *pgm mask. On these images, there is a small area marked with a transparent box with a magenta colored outline. My aim is to replace this box and outline with a black solid box and the rest of the image with white. (Tried to post samples here, but not enough reputation to do so.) I know how to do this "by foot" using gimp, but I cannot figure out a clever and simple way achieving this with imagemagick. I tried googling for solutions with -trim and -virtual-pixel, but no luck. Any help would be appreciated.
I'll do this step-by-step so you can see the intermediate parts in case you are on Windows and bash doesn't work. First, let's make make everything that is not within 10% of your magenta colour, namely rgb(225,75,130), into lime green: magick source.jpg -fill lime -fuzz 10% +opaque "rgb(225,75,130)" result.png Ok, now let's get the trim box - i.e. all the constant junk that ImageMagick could trim off to focus on the magenta bit. magick source.jpg -fill black -fuzz 10% +opaque "rgb(225,75,130)" -format '%#' info: 14x66+426+118 So your magenta box is 14x66pixels and located at offset 426,118 from the top-left. Now we want to get those in bash variables w,h,x,y. We need to change x and + into spaces using tr: read w h x y < <(magick source.jpg -fill black -fuzz 10% +opaque "rgb(225,75,130)" -format '%#' info: | tr 'x+' ' ') If we print this we get: echo $w, $h, $x, $y 14, 66, 426, 118 Now we want to draw a rectangle, but that needs top-left and bottom-right, so we need to do some maths: ((x1=x+w)) ((y1=y+h)) Ok, now we can load the original image, make it fully white, then draw our black rectangle: magick source.jpg -threshold -1 -fill black -draw "rectangle $x,$y $x1,$y1" -depth 8 mask.pgm So, the whole thing boils down to: #!/bin/bash read w h x y < <(magick source.jpg -fill black -fuzz 10% +opaque "rgb(225,75,130)" -format '%#' info: | tr 'x+' ' ') echo $w, $h, $x, $y ((x1=x+w)) ((y1=y+h)) magick source.jpg -threshold -1 -fill black -draw "rectangle $x,$y $x1,$y1" -depth 8 mask.pgm There are other (maybe more elegant) ways of doing it, using flood-fills and/or connected components but I didn't want it to rely on your magenta box being "watertight", i.e. not rely on the sides being continuous and complete. Also, if the size of your images is known and constant, you can avoid reloading the original and making it white by thresholding like I do in the last line and just create a canvas of the known dimensions, i.e.: magick -size ${W}x${H} xc:white -fill black -draw "rectangle $x,$y $x1,$y1" -depth 8 mask.pgm
Imagemagick - Inverse
I've a png image containing transparent pixels and colored pixels (mainly white). I'd like to transform all transparent pixels to white pixels and all white pixels to transparent pixels within a given rectangle. My idea would be to convert the white pixels to red the transparent colors to white and the red colors to transparent . Here' s my code: 1) convert ldl_0.png -fuzz 10% -fill red -opaque white lx.png 2) convert lx.png -background white -alpha remove -alpha off lx2.png However I can' t figure out how do I transform red colors to transparent. How do I do that? Also how can I force to do this only within a given rectangle? Thank You. -----
Try this in ImageMagick. Negate the alpha channel and turn the whole RGB channels to white. convert in.png -channel a -negate +channel -fill white -colorize 100 out.png
Set alpha according to gradient with imagemagick
Is it possible to set the alpha channel of an image according to a gradient with ImageMagick? I'd like the pixels on the left border of an image to be 100% transparent, and the ones on the right border to be 100% opaque, and with the ones in the middle having progressively lower transparency values. Or in a more general case - given a grayscale image, set the alpha channel of another image as a function of the B&W values (black = 100% alpha, white 0% alpha).
With ImageMagick you can use -sparse-color to apply a gradient only to the alpha channel to get the result you describe. convert in.png -alpha set -background none -channel A \ -sparse-color barycentric "0,0 none %[w],0 white" +channel out.png That command starts by activating the alpha channel and setting the background color to transparent. Then it uses -channel A to apply the following operation only to the alpha channel. The -sparse-color operation tells it to start with transparent at the far left edge, pixel 0,0 and graduate to opaque at pixel %[w],0. The %[w] means the width or far right edge. Although there are many ways to accomplish the effect you've described, by using -sparse-color you can easily make the gradient start and end at any positions on the image without having to create any intermediate masking images.
Simple. You would use -composite CopyOpacity to set the alpha channel from a gradient mask. Given I have the following images. image.png & transparent_mask.png We can set the image transparency (where black is alpha, and white is opaque) by copying values from the mask image to the input image alpha channel. convert image.png transparent_mask.png -compose CopyOpacity -composite output.png
Find nearest point horizontal in imagemagick?
I'm trying to find the nearest point to the point (red in this case) in this image. In this image this output find the first line point from right how I could do this output Please help me.
This looks fun! Let's dump the image to text using ImageMagick: convert image.png txt: # ImageMagick pixel enumeration: 337,218,65535,srgb 0,0: (65535,65535,65535) #FFFFFF white 1,0: (65535,65535,65535) #FFFFFF white 2,0: (65535,65535,65535) #FFFFFF white 3,0: (65535,65535,65535) #FFFFFF white 4,0: (65535,65535,65535) #FFFFFF white ... ... 221,79: (0,0,0) #000000 black 221,80: (0,0,0) #000000 black 221,81: (0,0,0) #000000 black 221,82: (0,0,0) #000000 black ... ... Ok, now let's use awk to find all black pixels and print their (x,y) coordinates: convert image.png txt: | awk -F'[,:]' '/black/{x=$1;y=$2;print x,y}' 221 79 221 80 221 81 221 82 221 83 221 84 ... ... Ok, now let's tell awk where the red pixel is by passing in rx (red x-coordinate) and ry (red y-coordinate). Then also, calculate the sum of the squares of the x-distance and y-distance from red to each black pixel. When it is less (i.e. nearer) than any seen so far, save the location. Print the nearest location at the end. convert image.png txt: | awk -F'[,:]' -v rx=318 -v ry=127 ' BEGIN{m=999999} /black/{ x=$1; y=$2; d2=(rx-x)*(rx-x)+(ry-y)*(ry-y) if(d2<m){m=d2;xm=x;ym=y} } END{print xm,ym}' 277 127 So, that is the answer... (277,127). Let's check it by drawing a cyan circle there: convert image.png -fill cyan -draw "circle 277,127 277,132" check.png On re-reading the question, I note that you actually only want the horizontally closest point whereas my solution above caters for the general case in any direction. If you just want horizontal offset, and you know the horizontal line is at y-coordinate 127, you can just extract that specific row from the image and simplify things like this: convert image.png -crop x1+0+127 txt: | awk -F'[,:]' -v rx=318 ' BEGIN{m=999999} /black/{x=$1;d=(rx-x)*(rx-x);if(d<m){m=d;xm=x}} END{print xm}' 277 If you don't like awk, you can just do it by eyeball... convert image.png -crop x1+0+127 txt: | grep -E "black|red" 221,0: (0,0,0) #000000 black 277,0: (0,0,0) #000000 black <--- nearest black to red 314,0: (65535,0,0) #FF0000 red 315,0: (65535,0,0) #FF0000 red 316,0: (65535,0,0) #FF0000 red 317,0: (65535,0,0) #FF0000 red 318,0: (65535,0,0) #FF0000 red 319,0: (65535,0,0) #FF0000 red 320,0: (65535,0,0) #FF0000 red How did I find the coordinates of the red pixel? I used ImageMagick's sub-image search looking for a red pixel like this: compare -metric rmse -subimage-search -dissimilarity-threshold 1 image.png \( -size 1x1 xc:red \) null: 0 (0) # 317,121 Notes: I just used the sum of the squares rather than the square root of the sum of the squares because it is computationally faster and the results are the same because it holds that if a>b, then a * a > b * b in this case. I used slightly different rx and ry from those generated by the sub-image search because OP says he had the coordinates and the ones found by sub-image search don't find the exact centre of the rather large red blob, but instead the top-leftmost edge of the red blob.
How to create PNG image with color_type=3 and bit_depth=1
The source is an RGBA PNG image (color_type=6 and bit_depth=8). I need an image with indexed color and 2 palette items (color_type=3, bit_depth=1). I tried with ImageMagick, but was able to reach only 1bit grayscale image (color_type=0, bit_depth=1) or 2bit indexed color image (color_type=3, bit_depth=2) in which only 2 colors are in use. According to the PNG specification such image is possible, but how to create it? Here is an image I am trying to convert: The result of "convert input.png -type palette -depth 1 output.png": The result of "convert input.png -type palette -depth 1 -colors 2 output.png" Both results have bit_depth=2, but the second one uses only 2 colors of 4 possible.
Use one of the following 3, ordered from least to most ancillary tags in the output file: convert -colors 2 -define png:include-chunk=none -verbose input.png output.png convert -colors 2 -define png:exclude-chunk=bkgd -verbose input.png output.png convert -colors 2 -background #000000 -verbose input.png output.png The root of this problem is that ImageMagick by default tags the image with a white background color (bKGD) PNG chunk (unnecessarily I'd say), and then adds this color to the palette if it's not already there, even if the image has no pixels of that color. Your particular image doesn't have white after converting to 2-color, so the unneeded background color tag becomes a 3rd color and it can no longer be saved as a 1-bit indexed color image. See also this from the author of IM. The reason others have failed to reproduce the problem is probably that they've tested with images where one of the 2 colors happened to be white. The 1st option with -define png:include-chunk=none avoids the problem by not outputting any ancillary PNG chunks at all (e.g. bKGD, gAMA, cHRM, tEXt, tIME). Like pngcrush -rem alla. I'd prefer this for a less cluttered file (without it IM will add a few of these even if they weren't in the input file). Note: There's also the simple -strip option which should avoid most of these, but as of v6.9.3 it won't cut bKGD due to a bug. The 2nd with -define png:exclude-chunk=bkgd removes only the offending background chunk. The 3rd option with -background #000000 retains all ancillary PNG chunks including bKGD but sets it black, one of the 2 colors present in your image, so it can still be 1-bit. Adjust the color for an image with neither white nor black in it. Note that for all these I'm including the -verbose switch. Not overly verbose; just goes from zero to two lines of status output where you'll notice a "2c" if the image stayed 2-color or a "3c" if not. It will also tell you if the palette reduction was lossy or not. It also outputs "8-bit sRGB" for most images, even paletted ones with fewer than 8 bits-per-pixel; that's not a bug as in your comment to another answer #johnfound, this refers not to the bits-per-pixel but to the bits-per-color component. It can be more than 8-bit for (rare) deep color images.
convert input.png -background white -type palette -depth 1 -colors 2 output.png works for me. (Why -depth=1 is not enough? No idea.) BTW, the tweakpng tool is useful for checking this kind of things. Update: if the images have transparency, you might play safer by removing it explicitly: convert input.png -background white -flatten -type palette -depth 1 -colors 2 output.png (You can replace white for your preference)
I think the command you need is this: convert input.png -type palette -depth 1 output.png If not, please post your input image and say how/where you find the color_type and bit_depth fields you refer to. Exiftool tells me this: ExifTool Version Number : 9.76 File Name : output.png Directory : . File Size : 2.3 kB File Modification Date/Time : 2015:01:10 19:20:33+00:00 File Access Date/Time : 2015:01:10 19:21:46+00:00 File Inode Change Date/Time : 2015:01:10 19:20:33+00:00 File Permissions : rw-r--r-- File Type : PNG MIME Type : image/png Image Width : 640 Image Height : 427 Bit Depth : 1 Color Type : Grayscale Compression : Deflate/Inflate Filter : Adaptive Interlace : Noninterlaced Gamma : 2.2 Background Color : 1 Datecreate : 2015-01-10T10:21:30+00:00 Datemodify : 2015-01-10T10:21:30+00:00 Image Size : 640x427 ImageMagick identify tells me this: Image: output.png Format: PNG (Portable Network Graphics) Mime type: image/png Class: PseudoClass Geometry: 640x427+0+0 Units: Undefined Type: Bilevel Base type: Bilevel Endianess: Undefined Colorspace: Gray Depth: 8/1-bit Channel depth: gray: 1-bit Channel statistics: Pixels: 273280 Gray: min: 0 (0) max: 255 (1) mean: 1.90168 (0.00745755) standard deviation: 21.9388 (0.0860345) kurtosis: 129.1 skewness: 11.4499 Colors: 2 Histogram: 271242: ( 0, 0, 0) #000000 gray(0) 2038: (255,255,255) #FFFFFF gray(255) Colormap entries: 2 Colormap: 0: ( 0, 0, 0) #000000 gray(0) 1: (255,255,255) #FFFFFF gray(255) Rendering intent: Undefined Gamma: 0.45455 Background color: gray(255) Border color: gray(223) Matte color: gray(189) Transparent color: gray(0) Interlace: None Intensity: Undefined Compose: Over Page geometry: 640x427+0+0 Dispose: Undefined Iterations: 0 Compression: Zip Orientation: Undefined Properties: date:create: 2015-01-10T19:20:33+00:00 date:modify: 2015-01-10T19:20:33+00:00 png:bKGD: chunk was found (see Background color, above) png:gAMA: gamma=0.45455 (See Gamma, above) png:IHDR.bit-depth-orig: 1 png:IHDR.bit_depth: 1 png:IHDR.color-type-orig: 0 png:IHDR.color_type: 0 (Grayscale) png:IHDR.interlace_method: 0 (Not interlaced) png:IHDR.width,height: 640, 427 png:text: 2 tEXt/zTXt/iTXt chunks were found signature: 3e08d7fea7bc7aeb0659ac2e2696084083d35ce30b0e3075dc561ad94259eaec Artifacts: filename: output.png verbose: true Tainted: True Filesize: 2.33KB Number pixels: 273K Pixels per second: 27.33MB User time: 0.000u Elapsed time: 0:01.009 Version: ImageMagick 6.8.9-8 Q16 x86_64 2014-11-10 http://www.imagemagick.org