How to convert coloured Captchas to Grey Scale? - image

I'm trying to make a capcha solver, but I have ran into some trouble. The captcha that I am trying to solve has different coloured backgrounds.
I need to convert it to black text on white background so that it could easily be recognised by tesseract-ocr
I have tried
convert *.png -threshold 50% *.png which only shows some of the digits.

The problem with simple 50% thresholding is that both colours may be lighter than 50% grey and will therefore come out as white. Or, conversely, both colours may be darker than mid-grey and therefore bith come out as black.
You need to do a 2-colour quantisation to get just 2 colours, then go to greyscale and normalize so the lighter colour goes white and the darker one goes black. I am not near a computer, to test, but that should be:
convert input.png -colors 2 -colorspace gray -normalize result.png
Now, you will find some images are inverted (black on white instead of white on black), so you can either test the top left corner pixel and if it is white, then invert the image. Or, you could get the mean of the image and if it is more than 0.5 that would indicate that the image is largely white and therefore needs inverting.
Invert with:
convert input.png -negate output.png
Get top-left pixel with:
convert image.png -format '%[pixel:p{0,0}]' info:-
Get mean value with:
convert image.png -format "%[mean]" info:-

Related

How to change colors of an image using RGBA and more channels independently of their color

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.

delete extra lines in image

I have an image with nearly smooth background with some extra lines on it. I want to convert the image from RGB color space to LAB color space and then average the "L" part of pixels.
But before converting I want to delete extra lines or somehow ignore lines pixels in averaging the "L" part. Is there any algorithm to do this?
Below is an example of the images I have.
An option is to compute the gradient (Sobel for instance) and avoid doing the accumulation where the gradient magnitude is significant.
Following the comment by #Paul, it will be interesting to see the influence of the threshold level on the computed average.
I am using ImageMagick like your other question.
This will give you a mask of all the pixels that differ by more than 5% from their surrounding area (it's the 0.05 in the -fx part). It works by loading the stone image, copying it and blurring the copy to remove local details. It then calculates the absolute difference between the original and the blurred copy and sets the pixel to 1 if the difference exceeds 5% else sets it to 0:
convert stone.jpg -colorspace gray \( +clone -blur x10 \) -fx "abs(u-v)>0.05?1:0" mask.png
Experiment with changing the 0.05 and see what you think.
This will tell you how many pixels in the mask are white. It relies on the mean being sum of pixel brightnesses divided by number of pixels and knowing all pixels are either 0 or 1:
convert mask.png -format "%[fx:int(mean*w*h)]" info:
6155
This will blacken all the masked pixels. It works by loading both the stone and the mask, inverting the mask and then, at each pixel position, choosing the darker of the two images - so it will choose black everywhere the mask is white and it will choose the stone everywhere else:
convert stone.jpg \( mask.png -negate \) -compose darken -composite nolines.png
In ImageMagick, if you make the pixels to be ignored transparent, you can get the average of all non-transparent pixels using -scale 1x1!. For example, from the two images above:
So first put the mask into the alpha channel, then scale the result to one pixel, turn alpha off and get the pixel color:
convert image.jpg mask.png -alpha off -compose copy_opacity -composite -scale 1x1! -alpha off -format "%[pixel:u.p{0,0}]" info:
srgb(231,214,198)
To check, lets make a swatch:
convert -size 100x100 xc:"srgb(231,214,198)" swatch.png
Or we can recolor the original image:
convert image.jpg -fill "srgb(231,214,198)" -colorize 100 newimage.png

Imagemagick: Converting specified color leaves slight border

I'm trying to overlay a green image over another image, and then convert the green color to transparent. The code I use is below. It works okay, however it leaves a slight green border. What's the best way to have this green border not show up? I tried using fuzz, however results with this vary. Sometimes it cuts out other colors. Is there a better way to prevent the green border than using fuzz?
convert image.png ../greenoverlay.png -layers merge image.png;
convert image.png -fuzz 41% -transparent \#00FF00 final.png;
Thank you all!

Extract the image2 from image 1

I want draw boundery box around the text like this image Image 2
from this Image 1. Can anyone suggest me a good way to do this or some algorithm or turorial anything?.
As you haven't suggested a tool, I will use ImageMagick straight at the command line as it is installed on most Linux distros and is available for OSX and Windows. It also has PHP, Perl, Python and .Net bindings.
So, as your background is uniform (ish) you can just use trim to trim it off:
convert image.jpg -fuzz 20% -trim result.jpg
Now you can add a border like this:
convert result.jpg -bordercolor black -border 5 result.jpg
Except you want the other grey background to be retained so that doesn't work for you. So, instead of actually trimming, we can ask ImageMagick where it "would" trim but to not actually do it like this:
convert image.jpg -fuzz 20% -format %# info:
81x22+1+14
So, we know it would make a 81x22px box starting 1 pixel in from the left and 14 pixels down from the top, so we'll just draw a rectangle there instead of trimming it:
convert image.jpg -fill none -stroke black -draw "rectangle 1,14 82,36" result.jpg
Or, if you want the outline fatter:
convert image.jpg -fill none -stroke black -strokewidth 5 -draw "rectangle 1,14 82,36" result.jpg
For a uniform background, a simple solution would be to identify all of the pixels that do not match the background color and then find the minimum and maximum indices in each axis of those pixels to define a rectangle.
For instance, if you were using Matlab, this might resemble:
Use 'find' to identify non-background pixels (e.g. linearIndices = find(~(image1 == background)) where background is either a hard coded set of RGB values corresponding to the background pixels or a set of RGB values identified by the mode of the image.
'Find' will return linear indices rather than subscripts (i.e. bottom right corner of a 3x3 matrix is 9, not [3,3]) so use 'ind2sub' to convert to subscripts (e.g. [I,J] = ind2sub(imageSize, linearIndices)
Use 'max' and 'min' to find range in x and y (e.g. rangeX = [min(I) max(I); rangeY = [min(J) max(J)])
Change pixels along min and max indices to border color. For instance, image1 ( rangeX(1), rangeY(1):rangeY(2) ) = boxColour (where boxColour is the RGB values of the colour you want the box to be) would draw the left border of the box. Repeat this process for the three other borders and you're done.
Of course this approach only works if the background is completely uniform. It also assumes you only want to draw a border that is one pixel thick.
While the function recommendations correspond specifically to Matlab functions, the thought process behind those functions could likely be ported elsewhere.

To remove background greyed pixels from image

I want to remove background unnecessary greyed pixels in above image.
May i know how to do that.
Quick and dirty with ImageMagick:
convert 9AWLa.png -blur x1 -threshold 50% out.png
Somewhat better, still with ImageMagick:
convert 9AWLa.png -morphology thicken '1x3>:1,0,1' out.png
Updated Answer
It is rather harder to keep the noisy border intact while removing noise elsewhere in the image. Is it acceptable to trim 3 pixels off all the way around the edge, then add a 3 pixel wide black border back on?
convert 9AWLa.png -morphology thicken '1x3>:1,0,1' \
-shave 3x3 -bordercolor black -border 3 out.png
Some methods that come to my mind are
If the backgroud is gray color rather than sparse black dots then you can convert the image in binary by thresholding it with proper value of grayscale. i.e. all values above particular values of pixel are white and all values below that are black. Something like this.
Another thing you can do is first smoothing the picture my some filter like mean or median filter and then converting into binary presented in previous point.
I think in this way the unnecessary background can be removed

Resources