I've a number of images with transparent pixels both inside the graphics and outside. One example is:
and
So now I want to fill only the internal transparent pixels (the ones within the black boarder), is there any batch processing way to do it? I tried imagemagick convert tool, but didn't figure out how to the the "selective" conversion.
Thanks for any help!
there are following ways how can accomplish that (it all depends on how the image is composed):
if you know the part you want to keep transparents starts at 0x0
You start by removing all transparency with something like http://www.imagemagick.org/Usage/masking/#remove
and then re-add the transparency using flood-fill starting at 0x0 http://www.imagemagick.org/Usage/masking/#bg_remove
You have more control over whats going on by using a transparency mask:
then you start modifying the mask (which is now only black/white), by coloringusing floddfill starting wiht 0x0 (i.e. with blue), replacing the black with white and then replacing all blue pixel with black (for color replacement see http://www.imagemagick.org/Usage/color_basics/#replace)
# the mask
convert original.png -alpha extract mask.png
convert mask.png -fill blue -draw 'color 0,0 floodfill' mask_blue.png
convert mask_blue.png -fill white -opaque black mask_filled_blue.png
convert mask_filled_blue.png -fill black -opaque blue mask_filled.png
# change transparent to skyblue
convert original.png -background skyblue -alpha remove -alpha off original_nontransparent.png
# apply the modified mask
convert original_nontransparent.png mask_filled.png -alpha Off -compose CopyOpacity -composite final.png
Note that this techniqe works only moderatly well with half transparent things (see http://www.imagemagick.org/Usage/antialiasing/#floodfill ).
For better results with half-transparency you might want to use different methods to "fill" the mask. You would i.e. just draw a shape instead of the two fill operations on the mask:
convert mask.png -fill black -draw "circle 40,80 60,60" mask_filled.png
this will fill the center, but keep the half transparency intact.
if you know the "center" is always trnsparent, you could also floodfill from the center.
Hope this helps
Related
Since it is hard to me to explain what I'm trying to do, I'm gonna show you this page to show you what I'm trying to reproduce and understand:
https://optifine.net/showCape?colTop=FF0000&colBottom=00FF00&colText=0000FF&colShadow=FD0000
which outputs this:
and this one https://optifine.net/showCape?colTop=FF00FF&colBottom=0034EE&colText=000000&colShadow=FF00E2 outputs this:
You can modify the hexadecimal colors, basically I'm trying to reproduce something like that. Basically you modify the colors and it gives you an image at the end with the colors you used.
I've tried to make the "possible" template that could be used on the page on Photoshop which can be downloaded here, it is a .psd file, that's because of the Alpha Channel, which I'm not even sure if done correctly. But based of these RGBA channels it should be possible to change the color. Can be downloaded here: https://workupload.com/file/4xYkgQMk
So what I know so far is that there is a template with RGBA channel. Each channel is indepedent so it apperantly doesn't matter if it's RGBA and at the end R channel is used to turn into another color other than red, where I'm not sure about that.
I've asked the developer he told me that these channels get interpolated with the real color after that, probably the one you choose.
Basically what is happening at showCape? and its URL parameters is that, lets assume colTop got assigned to the red channel then when you put a color in colTop it will get a fixed color that it will encode or something.
So the template has 4 Channels RGBA that can be made in Photoshop, the white color 255,255,255 means basically full and the black 0,0,0 means complete black. Like that you can setup brightness scales for the template.
I just don't know how to modify the channels and I don't understand how to use the Alpha channels properly or set them up.
I'm also not sure in which programming languages it is possible to peform and if you can test the template directly in something like Photoshop. Is it possible to do it in JavaScript or something to easy setup and if not on what then, to test it fast?
Ok, so here's how you can generate that sort of thing with ImageMagick, which is included in most Linux distros and is available for macOS and Windows. Note that there are Python, PHP, node.js and other bindings available.
First, generate a red rectangle:
magick -size 200x150 xc:red red.png
Now see how to do the same thing with hex codes:
magick -size 200x150 xc:"#ff0000" red.png
Now, draw a red rectangle with a blue one on top:
magick -size 200x150 xc:red -fill blue -draw "rectangle 10,10 80,140" redandblue.png
Now make the blue transparent:
magick -size 200x150 xc:red -fill blue -draw "rectangle 10,10 80,140" -transparent blue redandtrans.png
Now make a gradient from lime green to magenta:
magick -size 200x150 gradient:lime-magenta gradient.png
Now overlay the red rectangle with transparent window onto the gradient:
magick gradient.png redandtrans.png -composite overlay.png
Now add text:
magick overlay.png -fill "#0000ff" -pointsize 16 -draw "text 90,40 'Coloured text'" result.png
And now do the whole thing again, in one go:
magick -size 200x150 gradient:lime-magenta \
\( xc:red -fill blue -draw "rectangle 10,10 80,140" -transparent blue \) \
-composite \
-fill "#0000ff" -pointsize 16 -draw "text 90,40 'Coloured text'" result.png
Now you have provided a template, I can separate out the channels with ImageMagick like this and append them side-by-side with Red channel on the left, then Green, then Blue then the alpha/transparency channel on the right. I also added a red box around each one so you can see the extent on StackOverflow's white background.
magick template.png -separate -scale 100x +append channels.png
Keywords: ImageMagick, absolute basics, tutorial, transparency, compose, overlay, command line, image processing.
this sounds like indexed colors / palette effect from the VGA days (like plasma, water and fire) Where you change the palette (in a specific way) and image changes with it.
The idea is that Your image/sprite does not contain RGB colors directly but color indexes from palette instead. Where part of the palette for your image/sprite contains a color gradient so gradients on image are also gradients on index (neighboring shades have also neighboring indexes). Many old pixelart sprites and images from the old days are done this way (sorted palette).
Now you can simply chose few colors in that part of palette and interpolate the rest of the gradient (linearly or better).
To mimic this your need:
have a indexed color pixel art with sorted palette
For example You can convert your image into BMP or GIF with palette and sort the colors.
detect the part of palette with color gradient
change/update the gradient
re-render or recolor image.
we run a mogrify batch job like mogrify -path "WEBREADY\DONE" -layers merge -trim +repage -resize "1200x1200>" -define jpeg:extent=500kb -format jpg *.*
This works fine for images with a white background. But recently we saw a 2% error rate and discovered the error. Mogrify trims as expected only on the web the images is surrounded by white so this looks quite silly with grey-ish in corners.
THe solution would be to either
Detect the non-white background. And in that case -only- do not trim
Or to detect the background color (it is JPG) in top left corner and forst set this to an all white background.
Can this be done in my 1 command above for the commandline? (so find the grey background first and change it to white)
You can get the colour of the top-left pixel like this:
convert shirt.jpg -crop 1x1+0+0 txt:
# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (57311,57311,57311) #DFDFDF srgb(223,223,223)
So, it is #DFDFDF.
If you now try and replace that shade with yellow (I know you want white but you can't see that on here):
convert shirt.jpg -fill yellow -opaque "#DFDFDF" result.png
and you can now see the problem. The background is not uniform and its colour also appears in your shirt. If you add some fuzz, it makes it more pronounced:
convert shirt.jpg -fill yellow -fuzz 10% -opaque "#DFDFDF" result.png
Even if you try flood filling from the top-left, you still have to hope that there are no pixels in the edges of your shirt that are similar to that corner:
convert shirt.jpg -fill yellow -fuzz 5% -floodfill +0+0 "#dfdfdf" result.png
I have a series of images in PNG format that make up an animation.
I want to automate the process of cropping the excess transparency in the animation as a whole, so I need to find the unique smallest rectangular area such that, if every image were cropped to it, no opaque pixels would be trimmed from any image; then crop every image to this area.
IOW, the equivalent of making each PNG a layer in GIMP, doing "autocrop layer" on every layer, then "canvas size to layers", and reexporting every layer as a PNG again.
Is there a way to get mogrify or convert (or GIMP, for that matter, but I imagine in my case the number of images involved would take up too much memory to have them all as GIMP layers) to do this automatically?
If not, is there a scripting function that would return the autocrop rectangle for a given image, so I could check overlaps and find the smallest that would cover all of them, myself?
You can get the cropping box for an image like this:
convert input.png -format "%#" info:
245x114+4+2
So, in this instance it is 245px wide by 114px tall and offset [4,2] from the top-left corner.
So, to test the theory, let's make 3 images with transparent background and little red boxes to represent your content. I have added a black border just so you can see the extent on Stack Overflow's white background:
convert -size 200x100 xc:none -fill red -draw "rectangle 10,10 20,20" 1.png
convert -size 200x100 xc:none -fill red -draw "rectangle 180,20 190,30" 2.png
convert -size 200x100 xc:none -fill red -draw "rectangle 150,80 160,90" 3.png
So, I can get the cropping box for all 3 images combined like this:
convert [123].png -evaluate-sequence mean -format %# info:
181x81+10+10
And if I draw that on in blue:
convert result.png -stroke blue -fill none -draw "rectangle 10,10 191,91" -bordercolor black -border 1 result.png
I need to take a normal image:
and add a white, transparent overlay so it looks something like this:
Don't pay attention to the text on the converted image or the fact that it's a cropped version of the original. I need to simply convert the top to the exact same image, just with this white, transparent overlay. I also need it to be a cli command.
Updated Answer
This is even easier
convert house.jpg -fill white -colorize 80% result.png
Original Answer
Something like this maybe...
convert house.jpg \( +clone -fill white -colorize 80% \) -composite result.png
This is general question (between programming and math):
How to replace a color by another in a bitmap?
I assume the bitmap is a 2D-array
Example : Let's replace RGB color [234,211,23] by RGB color [234,205,10].
How to do this color replacement, such that the neighbour colors are replaced as well ? I.e. a smooth color replacement.
I assume there exists methods like linear interpolation for neighbour colors, etc.
What are the classical ways to do this?
Here is an example of how to detect color RGB 234,211,23 and its neighbour colors in a 500x500px image bitmap array x:
for i in range(500):
for j in range(500):
if abs(x[i,j][0] - 234) < TRESH and abs(x[i,j][1] - 211) < TRESH and abs(x[i,j][2] - 23) < TRESH:
x[i,j] = ... # how to set the new color in a smooth way?
I think that a good approach that you can use is to change the whole image to a new color space, I'd rather use HSV color space instead of RGB, you can find some info here: HSV color Space.
When you wish to search for a specific color, RGB model is not the best option the principal reason is the large changes between brightness and darkness of the color. The thresholds on the RGB color space are not useful in this case.
In HSV color space you have a channel to select the color of your interest and the other 2 channels are for the saturation and brightness of the color. But you can get accurate results only using the Hue channel (the first). The only thing that you need to take care about is in realize that you need to work this channel as a circular buffer because the maximum and minimum value are very similar in color, both are the red color.
Once you have the detected color you can set the new one and you can keep the saturation and brightness properties of the old color, by doing this the color changes will look like smoother.
If you wish to replace the colours of pixel in a 2D - Array you do so as following:
Array[x][y] = new value
where x and y stand for the location of the pixel, but keep in mind that images use the right-handed system thus the values of y grow bottom to top while in computers you use the left handed system so y values grow from top to bottom. The exact syntax of assigning the value of the new colour depends on the programming language you are using (the example above works in ruby). Also some programming languages already offer image manipulation functions built in so make sure to read the documentation to avoid implementing an already implemented function.
New Answer
New answer coming - now I understand that you mean the neighbours in the colour sense rather than the geometric sense...
You could calculate the vector colour distance from each pixel of your image to the colour you want to change and use that as a mask. So, if we create the same image as below... say we have a red-yellow gradient as background with a blue square on it and we wish to replace the central orange colour across the middle.
# Make red-yellow gradient with blue square within
convert -size 500x500 gradient:red-yellow -fill none -stroke blue -strokewidth 10 -draw "rectangle 100,100 400,400" image.png
Now clone that image, and fill the clone with the orange tone we want to replace, then calculate the vector colour distance from each pixel to that orange tone:
convert image.png \( +clone -fill "rgb(255,128,0)" -colorize 100% \) \
-compose difference -composite \
-evaluate Pow 2 -separate \
-evaluate-sequence Add -evaluate pow 0.5 \
-negate \
colour_distance.png
You can then use this colour_distance.png as a mask for alpha-compositing, so if we decide to replace that orangey tone with pink, we can do this:
convert image.png \
\( +clone -fill fuchsia -colorize 100% \) \
\( colour_distance.png -sigmoidal-contrast 20 \) \
-composite z.png
Note that I changed the pow 0.5 to pow 0.3 to roll off the mask more sharply.
Original Answer
Here's one way to do it. Say we have a red-yellow gradient as background with a blue square on it and we wish to replace the blue with green...
First, extract all the blue pixels onto a transparent background, then change them to green and blur them so they spread into the neighbouring pixels. Then overlay the blurred green pixels onto the original image.
I choose to do it with ImageMagick but you seem happy to adapt to other languages and libraries...
#!/bin/bash
# Make red-yellow gradient with blue square within
convert -size 500x500 gradient:red-yellow -fill none -stroke blue -strokewidth 10 -draw "rectangle 100,100 400,400" image.png
# Make everything blue green, then everything else transparent, then blur the lot
convert image.png -fill green -opaque blue -fill white +opaque green -transparent white -blur x6 x.png
# Now overlay the blurred greeness onto the original after replacing blues with green
convert x.png \( image.png -fill green -opaque blue \) -compose overlay -composite result.png
Image.png
x.png (the blurred, colour-replaced image)
result.png