How to change white background to transparent in golang? - image

How to change a Golang image.Image's white background to transparent?
I want to put the white background into a translucent color, do you have any suggestions?

This is not possible in general but there are heuristic approaches to attempt this.
Why is it not possible?
If the original image had some transparent pixels and was rendered on a plain white background (or any known background) then in the resulting image there is lost information. For example, is a pink pixel created from a red pixel with some transparency or a truly pink pixel without transparency?
Even a pure white pixel may have been fully white originally, or fully transparent, or somewhere in between.
Heuristic approaches
If you know something about the original image or can infer something by looking at it you may be able to deduce what colour and transparency of the original pixels was. A simple first step is that if the outside pixels are white then you might want to flood fill this area with fully transparent pixels. Also white areas inside coloured areas may be holes that can also be transparent.
Next you can infer the colours of border pixels around objects of a single colour (assuming transparency was used for anti-aliasing). For example for a red circle with pink pixels on the circumference it's likely they were originally red with some transparency leading them to be rendered in different shades of pink. For more complex, multi-coloured shapes you can get a reasonable result by manually editing the image using judgement, knowledge/guesswork of the original image and knowledge of how anti-aliasing was performed.
I wrote a Paint.Net plugin (C#) to automate this sort of thing many years ago and sometimes it gave reasonable results, but often you need to do it by hand.

package "image" has Decode function
func Decode(r io.Reader) (Image, string, error)
image.Image is interface
type Image interface {
// ColorModel returns the Image's color model.
ColorModel() color.Model
// Bounds returns the domain for which At can return non-zero color.
// The bounds do not necessarily contain the point (0, 0).
Bounds() Rectangle
// At returns the color of the pixel at (x, y).
// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
At(x, y int) color.Color
}
after you decode you file into image.Image, you can get Height and Width from Bounds(),and color from At(x,y).
So, here is what to do next:
make another image with alpha channel,
Iterate throw whole image one pix by another,
check color, copy color to new image after you do whatever you want.

Related

Removing semi-transparent overlay on flattened image

A solution to this problem seems to not exist but I find it hard to believe it is not possible.
Imagine you have an image with a semi-transparent overlay (color=black, transparency=50%), whether over the whole image or just a portion, doesn't matter. How could one convert the pixels underneath to their original color, in essence removing the black overlay.
Just like a simple algebra equation we should be able to rearrange the variables to solve for the "original pixels" under the overlay. Something along the lines of -
original pixels * semi-transparent overlay = new pixelsoriginal pixels = semi-transparent overlay / new pixels
Obviously such an equation over simplifies the problem but I think that gets my point across. Since we know the color and percent transparency, why couldn't we "retrieve" the colors of the underlying pixels?
EDIT: Mark Ransom in the comments is correct, if you know the transparency is 50% then simply multiplying by 2 gets you to the original color. Any recommendations on how to apply this to a whole region in Photoshop or GIMP? Certainly doing it pixel by pixel is out of the question.
Thank you!
The "divide" layer mode will do what you want. In the case of semi-transparent black, use a gray with the value equal to the opacity value of the overlayed layer.

Detecting anti-aliased or undersampled text image

I have an image that is essentially a text document (black and white) but due to anti-aliasing/undersampling applied during scanning, the image contains a lot of color, light tone pixels and is thus saved as a full-color image i.e: takes a lot of space.
My goal is to be able to detect Black and White image candidates in order to convert them from full color to B&W which dramatically reduces their size.
Is there a way to detect such anti-aliased/undersampled images? Doing color pixel analysis doesn't help because the colored pixels end up being close in amount to the black pixels... Essentially I want to be able to detect that the colored pixels come from anti-aliasing/undersampling a black & white image and not from a picture type image.
Here is an example image:
As you can see there are many more colors than just black. However this image is a good candidate for Black & White / Greyscale conversion instead of full color. How can I detect such images? Please note that in this example the colors tend to be on the grey side but there are many cases where they are cyan or brown etc.
I think it is a valid question. I don't have 50 reputation to post a comment so I will post this as an answer.
Basically, in a black and white anti-aliased image the various grey colors are opacity differences of the black color. If we observe those pixels they will be like these listed below. So, if the operation is a color manipulation then apply the same opacity picked up from those grey pixels to the new color.
rgba(0,0,0,0.6)
rgba(0,0,0,0.9)
rgba(0,0,0,0.5)
rgba(0,0,0,0.9)
rgba(0,0,0,0.6)
rgba(0,0,0,0.1)
rgba(0,0,0,0.5)
In my opinion, the pixels other than grey, in this example image, cyan and brown as it appears can be safely ignored because they seemed like not part of the original text. If there were a few more example images of non grey pixels would have been good. But if we cannot ignore them just need to get the pixel opacity and apply the same color manipulation. In other words we treat them as black pixels.

a black image's color can not be changed in Unity

the color of a black image , or the black part of a image, can not be changed.
I set the image's color to red, but the image is still black.
Is that a desired feature?
What i want is , the image is changed to red.
the Unity version is 5.0.1f.
I am using the new UI.
To understand the source of the problem, you have to understand how "changing colors" work. It's nothing but a simple multiplication. In RGB terms, "black" is a vector of (0, 0, 0) — and it's pretty obvious, that whatever you multiply the 0 by, it stays black.
If you want the template image to be able to change to any color, use white.
To modify colours in a more complex way, you have to understand how the Color property of a Image component works. UI system hides a lot of complexity underneath (and it's good). Basically, Color modifies the vertex colours of a mesh. Since you don't usually specify a material, a default sprite material is used, and it uses a default sprite shader. And inside this shader, when it paints the pixels on the screen, it multiplies the vertex colours by the texture colour sampled at this pixel, and that's how it produces the end result. If you want the colours to be combined in a different way, you'll have to write a custom shader — which is really not as hard, but you probably don't need it for what you're trying to do in the scope of this question.
Black stays black.
White, however, will change with whatever Color you choose, so if you use an image editor and make your image be white instead of black, the image can then be whatever color you choose within Unity.
Check to see if your image has an alpha channel. You can do this with GIMP or Photoshop. If it does, then check your shader/material to ensure that it's set to transparent/diffuse (and not just diffuse). Diffuse only doesn't apply the alpha property to the material.
Also, it doesn't look like you assigned a material...
Make sure you have used yourImage.canvasRenderer.SetColor.
For example:
damageAnim.canvasRenderer.SetColor (new Color (255, 255, 255, 255));

Best natural way of coloring an icon/sprite

I wanna to color a sprite/icon with a transparent background and with shadows. I tried to shift the hue to all pixels but it looks not so natural and I have problems with the black and the white colors in an image. If an image tend to be black shifting the hue do not change the black in red or another color even shifting by 360 degrees.
Tried to color addicting and subtracting color and even in that case the black and the white tend to be colored or disappears at all.
Maybe should I put an image on the icon to achieve the coloring effect ?
Any suggestions on how to proceed.
I lost.
You've been asking a lot about this hue shifting thing, so I figured I'd try to work out an example: http://jsfiddle.net/EMujN/3/
Here's another that uses an actual icon: http://jsfiddle.net/EMujN/4/
There's a lot in there. There's a huge data URL which you can ignore unless you want to replace it. Here's the relevant part where we modify HSL.
//SHIFT H HERE
var hMod = .3;
hsl[0]=(hsl[0]+hMod)%1;
//MODIFY S HERE
var sMod = .6;
hsl[1]=Math.max(0,Math.min(1,
hsl[1]+sMod
));
//MODIFY L HERE
var lMod = 0;
hsl[2]=Math.max(0,Math.min(1,
hsl[2]+lMod
));
I've converted to HSL because it's a lot easier to accomplish what you want in that color space than RGB.
Without getting any more complex, you have three variables you can tune: how much to add to either Hue, Saturation, or Lightness. I have the lightness variable set to 0 because any higher and you will see some nasty JPEG artifacts (if you can find a decent .png that would be better, but I went with the first CC night image I could find).
I think the hue shift (yellow to green) looks pretty good though and I have maxed out the saturation, so even a normally white light appears bright purple. Like I said in my comment, you will need to increase the lightness and saturation if you want to colorize patches of black and white. Hopefully, you can figure out what you need from this example.
image used: http://commons.wikimedia.org/wiki/File:Amman_(Jordan)_at_night.jpg
I found a better solution by myself which can solve the problem with the black and white.
So basically the solution can be solved in multiple steps. Here I will define the steps. Later I'll provide some working code:
Get the image
Calculate the predominant color, averaging the image pixels or simply providing an input RGB value which is the predominant that your eye can catch.
If the predominant tends to be black or white, or both, the image has to be recolored with an addictive or subtractive method, addictive if black, subtractive if white. So basically all RGB pixels should be attenuated or sharpened until RED. I think that the best solution should be RED, because RED is first in the HUE scale, and this can help when we will hue-shift the pixels.
To have a unique algorithm which can work with different kind of images, not only black predominant or white, ideally the input the non-black and non-white predominant images should be pre-hueshifted manually, using photoshop or with another algorithm in a way that the new predominant color results to be RED too
After that the Hue shifting coloring is straighforward. We know that the predominant color is RED for all the images, and we'll shift the HUE values with a difference between the HSV value of the desired color and the HSV of the predominant color (RED).
Game over. We have a pretty universal way to color different images with hue shifting in a natural way.
Another question could be how to authomatically pre-shift the input images which predominant color is not black or white.
But this is another question.
Why this coloring method could be considered natural. Simply consider one thing. Generally the non dominant black or white colors are part of the shadows and light which gives a 3D feel to the images. On the other hand if my shoes are 100% black and i will tint them with some colors, they will no more be black. Color the dominant black cannot be achieved simply shifting the HSV parameters but other steps should be performed. The steps are the above described.

Edge Detection and transparency

Using images of articles of clothing taken against a consistent background, I would like to make all pixels in the image transparent except for the clothing. What is the best way to go about this? I have researched the algorithms that are common for this and the open source library opencv. Aside from rolling my own or using opencv is there an easy way to do this? I am open to any language or platform.
Thanks
If your background is consistend in an image but inconsistent across images it could get tricky, but here is what I would do:
Separate the image into some intensity/colour form such as YUV or Lab.
Make a histogram over the colour part. Find the most occuring colour, this is (most likely) your background (update) maybe a better trick here would be to find the most occuring colour of all pixels within one or two pixels from the edge of the image.
Starting from the eddges of the image, set all pixels that have that colour and are connected to the edge through pixels of that colour to transparent.
The edge of the piece of clothing is now going to look a bit ugly because it consist of pixels that gain their colour from both the background and the piece of clothing. To combat this you need to do a bit more work:
Find the edge of the piece of clothing through some edge detection mechanism.
Replace the colour of the edge pixels with a blend of the colour just "inside" the edge pixel (i.e. the colour of the clothing in that region) and transparent (if your output image format supports that).
If you want to get really fancy, you increase the transparency depending on how much "like" the background colour the colour of that pixel is.
Basically, find the color of the background and subtract it, but I guess you knew this. It's a little tricky to do this all automatically, but it seems possible.
First, take a look at blob detection with OpenCV and see if this is basically done for you.
To do it yourself:
find the background: There are several options. Probably easiest is to histogram the image, and the large number of pixels with similar values are the background, and if there are two large collections, the background will be the one with a big hole in the middle. Another approach is to take a band around the perimeter as the background color, but this seems inferior as, for example, reflection from a flash could dramatically brighten more centrally located background pixels.
remove the background: a first take at this would be to threshold the image based on the background color, and then run the "open" or "close" algorithms on this, and then use this as a mask to select your clothing article. (The point of open/close is to not remove small background colored items on the clothing, like black buttons on a white blouse, or, say, bright reflections on black clothing.)
OpenCV is a good tool for this.
The trickiest part of this will probably be at the shadow around the object (e.g. a black jacket on a white background will have a continuous gray shadow at some of the edges and where to make this cut?), but if you get this far, post another question.
if you know the exact color intensity of the background and it will never change and the articles of clothing will never coincide with this color, then this is a simple application of background subtraction, that is everything that is not a particular color intensity is considered an "on" pixel, one of interest. You can then use connected component labeling (http://en.wikipedia.org/wiki/Connected_Component_Labeling) to figure out seperate groupings of objects.
for a color image, with the same background on every pictures:
convert your image to HSV or HSL
determine the Hue value of the background (+/-10): do this step once, using photoshop for example, then use the same value on all your pictures.
perform a color threshold: on the hue channel exclude the hue of the background ([0,hue[ + ]hue, 255] typically), for all other channels include the whole value range (0 to 255 typically). this will select pixels which are NOT the background.
perform a "fill holes" operation (normally found along blob analysis or labelling functions) to complete the part of the clothes which may have been of the same color than the background.
now you have an image which is a "mask" of the clothes: non-zero pixels represents the clothes, 0 pixels represents the background.
this step of the processing depends on how you want to make pixels transparent: typically, if you save your image as PNG with an alpha (transparency) channel, use a logical AND (also called "masking") operation between the alpha channel of the original image and the mask build in the previous step.
voilà, the background disappeared, save the resulting image.

Resources