How to blur/pixelate part of an image using ImageMagick? - image

I am using Perl and ImageMagick (Perl-API).
In a first step i would like to take a rectangle of an image and blur this part of the image. Desired result is the original image with the rectangle blured.
In a second step i need to blur a part of an image with a turned rectangle (i.e. turned by 35%).
How can i achieve this?

Best way I can think of is to leverage masks to blur against. This would allow you to "draw" a shape, and pass through what to be blurred.
Example:
# Create base image
convert rose: -sample 200x rose_large.png
# Create mask
convert -size 200x131 xc:black -fill white -draw 'circle 100 65 100 25' rose_mask.png
# Blur with mask
convert rose_large.png -mask rose_mask.png -blur 0x8 +mask rose_blur_mask.png
Other techniques and examples here. I'm not familiar with Perl API, but there should be a Mask method that accepts an image handler parameter.
Update
For rectangle, you would simply update the shape to draw on the mask. Here's an example where I'm only blur-ing what's inside a rectangle.
# Create rectangle mask
convert -size 200x131 xc:white -fill black -draw 'rectangle 50 30 150 100' rose_rectangle_mask.png
# And repeat blur apply
convert rose_large.png -mask rose_rectangle_mask.png -blur 0x8 +mask rose_blur_retangle_mask.png

As you asked for PerlMagick, I pulled my last few remaining hairs out to try and do this in Perl... the files 1.png, 2.png and 3.png are purely for debug so you can see what I am doing.
#!/usr/bin/perl
use strict;
use warnings;
use Image::Magick;
my $x;
my $image;
my $blurred;
my $mask;
# Create original fishscale image
$image=Image::Magick->new(size=>'600x300');
$image->Read('pattern:fishscales');
$image->Write(filename=>"1.png");
# Copy original image and blur
$blurred = $image->Clone();
$blurred->GaussianBlur('x2');
$blurred->Write(filename=>"2.png");
# Make mask and rotate
$mask=Image::Magick->new(size=>'600x300');
$mask->Read('xc:white');
$mask->Draw(fill=>'black',primitive=>'rectangle',points=>'100,100,200,200');
$mask->Set('virtual-pixel'=>'white');
$mask->Rotate(20);
$mask->Transparent('white');
$mask->Write(filename=>"3.png");
# Copy mask as alpha channel into blurred image
$blurred->Composite(image=>$mask,qw(compose CopyOpacity gravity center));
# Composite blurred image onto original
$image->Composite(image=>$blurred);
$image->Write(filename=>'result.png');
Here are the debug images...
1.png
2.png
3.png
result.png
There may be a much faster, simpler, more efficient way of doing this, but I don't know it, and there are precious few examples of PerlMagick out there, so I'll stick my marker in the sand and see if anyone can better it:-)
P.S. Don't feel bad about my hair - there were only three left anyway :-)

Related

How to give an image an old, dusty appearance with faded colours?

I have images of old paintings. The paintings are old and dusty with faded colours as shown here.
How do I give any image this type of an 'old' appearance? I couldn't find any filters or openCV functions to achieve this type of look?
EDIT: My question is different as the other one solves the problem using the sepia filter and using the grain effect. I'm not looking for that sort of an appearance. I want my image to look like an old damaged painting. This means that the colours should be faded and it should have an overall dusty appearance.
There's no real need to write any code and use OpenCV, since you can do all that on the command-line with ImageMagick which is installed on most Linux distros and is available for macOS and Windows.
First, fading. This can be simulated by reducing the saturation of an image. So if we start with this Mona Lisa image:
We can fade her using this command to leave the brightness unchanged at 100% of its original value and reduce the saturation to 50% of its original value. I am intentionally "over-egging" everything so you can see it clearly. You should maybe be more subtle.
convert mona.jpg -modulate 100,50 result.jpg
Next, vignetting - or dark corners. You can use something like this:
convert mona.jpg \
\( +clone -fill white -colorize 100 -background "gray(50%)" -vignette 0x15+1+1% \) \
-compose multiply -composite result.jpg
The 0x15 controls the roll-off, or how gradual the change is, so increase the 0x15 if you want a smoother roll-off or go down to 0x5 if you want it harder. The +1+1% means that the ellipse will be 1% smaller than the width of the image and 1% smaller than the height of the image. So if you want a smaller light hole and bigger dark corners, go for +10+10%. The degree of darkening is controlled by the gray(50%) so you can diddle with that till you are happy too :-)
Finally, dust. Best thing is to get a PNG image of some dust, resize it to match the size of your image and overlay it.
First get the size of Mona:
identify mona.jpg
mona.jpg JPEG 403x600 403x600+0+0 8-bit sRGB 57130B 0.000u 0:00.000
So, she is 403x600. Here is a sample of some dust - again, you can be more subtle - I am just being heavy-handed so it shows:
Let's resize the dust to match and overlay it:
convert mona.jpg \( dust.png -resize 403x600\! \) -composite result.jpg
Then you can combine all three effects, fading, vignetting and dust, into a single command:
convert mona.jpg -modulate 100,50% \
\( +clone -fill white -colorize 100 -background "gray(50%)" -vignette 0x15+1+1% \) \
-compose multiply -composite \
\( dust.png -resize 403x600\! \) -composite result.jpg
If you have lots of images to process, you can script the whole lot to be done in parallel very easily with GNU Parallel - see some of my other answers for examples.
Keywords: artificial ageing, image ageing, command-line, command line, ImageMagick, magick, old, old photo, photo effect, convert, dust, scratches, fading, faded.
I would suggest using a style transfer tool, rather than manually coming up with a procedure to mimic the style of an old painting. There are plenty free style transfer tools and libraries available.
I would suggest using OpenCV various filters to create the effect you need. You have to try various filters and try to figure what works for you, But I have suggestions which you can try.
For color, fading try Erode and Dilate with small kernel size.
Next, add some noise, Salt and Pepper will do just fine, also try gaussian filter after applying noise. Salt and Pepper is non-linear noise and Gaussian is a linear filter so it will just spread the noise, but keep the filter kernel small.
Try finding some images of dust, torn page edges (WITHOUT BACKGROUND) like in the following link:
https://www.google.co.in/searchq=dust+png+images&newwindow=1&rlz=1C1CHBF_enIN797IN798&source=lnms&tbm=isch&sa=X&ved=0ahUKEwjtq7ZvfPcAhXJO48KHQ2UD0kQ_AUICigB&biw=1536&bih=759#imgrc=_
Keeping alpha transparency in mind, mask these over your images.
With all the things in correct proportion and sequence, You will get your old dusty image.

imagemagick gradient mask file creation

I'm playing with this creative script here: http://www.fmwconcepts.com/imagemagick/transitions/. The plan is to mimic what happens with the script with ffmpeg and generate video with transition effects between pictures. My current understanding is this:
I have two pictures A and B.
I need in between a couple of pictures (say 15) that are partially A and partially B.
To do that I use the composite -compose src-over A.jpg B.jpg mask-n.jpg out.jpg command.
During the process, the mask-n.jpg gets generated automatically that gradually change from all black to all white.
Depends on the mathematically equations, the way the transition effect looks is different.
In one of the example, Fred the author gave this:
convert -size 128x128 gradient: maskfile.jpg
This will generate a image like this:
This is partially black and partially white. For the transition to work, I'll need an all white one and an all black one and a couple of others in between. What's the magical command to do that?
I have re-read your question and I am still not sure I understand, but maybe you want a dark grey to light grey gradient:
convert -size 128x128 gradient:"rgb(40,40,40)-rgb(200,200,200)" greygrad.png
Not sure I understand what you are trying to achieve, but if you want an all black one, use:
convert -size 128x128 xc:black black.jpg
and an all white one:
convert -size 128x128 xc:white white.jpg
and a grey one:
convert -size 128x128 xc:gray40 gray40.jpg
If you want to join them for transitions, use
convert im1.jpg im2.jpg -append result.jpg
or use +append to join side by side instead of above and below.
Consider using PNG instead of JPEG throughout.
Fred tells you how the script works at the bottom of the page you have linked to with some example code.
According to his explanation there is only the one mask images as:
The mask images is gradually made lighter

Change Pixel Values of Image to remove Date

What is the most efficient technique to remove the date that a Camera embeds on any image it takes.
The task is to prepare a script/code/software that shall remove the date from the given input image file (jpeg, png).
Please let me know an optimum way to accomplish this.
Thank you.
Here is an alternative approach to the question. You can determine the average colour of the bottom right corner of the image (size 250px wide x 100px high) with Imageagick like this:
ave=$(convert sign.jpg -gravity southeast -crop 250x100+0+0 -scale 1x1 -format "%[pixel:p{0,0}]" info:)
That will give you the value srgb(199,181,119) for this image. Now you can create a rectangle (200px x 50px) that colour and overlay it onto the image and then blur the edges a little to blend it in:
convert sign.jpg \( -size 200x50 xc:"$ave" \) -geometry +970+780 -composite -region 240x90+950+760 -blur 0x10 out.jpg
I am not sure if you were hoping for something that is forensically indetectable or something that more or less removes the distraction somewhat. Hopefully the latter :-)
A little measuring around shows that the date is located at the following position:
150x40+650+520
i.e. 150 pixels wide by 40 pixels high, located 650 pixels to the right of the top left corner and 520 pixels down from the top left corner.
So, one approach would be to copy the piece of the image directly below that, and paste it on top of the date, which can be done in ImageMagick in one command like this:
convert sign.jpg \( +clone -crop 150x40+650+560 +repage \) -geometry +650+520 -composite out.jpg
That says... take the original image and create a copy of it (+clone), then cut out the piece specified after the crop command command and reset that as though it was the top left corner (+repage). Then paste (-composite) that image at offset +650+520 on top of the original image and save the result as out.jpg.
It is not a beautifully engiineered solution, but may be good enough. It may be desirable to blur the area a little, to help disguise it. Alternatively, it may be possible to select the colours within the date and make them transparent, then to displace the original image a little behind the transparent holes to fill them - I didn't choose that option because it is harder and because you may not like ImageMagick anyway, and there are actually several colours within the date field ranging from browns to golden yellows and selecting them without affecting the remainder of the image might start getting fun!
ImageMagick is free and available for Windows, OSX, Linux etc from here. It is ready installed on most Linux distros anyway.

Using ImageMagick to add whitespace to images in bulk

I have a bunch of images that are rectangular and I need them to be square, i.e. 1000x1000, so I've decided to use ImageMagick to pad the sides of the image with the amount of whitespace necessary to make the image square.
I've found the code from the following link useful (see next paragraph). But this requires me to process each image individually, to set the filename and then the -thumbnail dimensions. How can I use this same process to process an entire folder?
Here's the code and the link to it:
http://imagemagick.org/Usage/thumbnails/#pad
convert -define jpeg:size=200x200 hatching_orig.jpg -thumbnail '100x100>' \
-background white -gravity center -extent 100x100 pad_extent.gif
It is not very clear from your question what you actually have (i.e. how big your images are? what format are they?), nor what you actually want (you only provide an example that doesn't do what you want. But I'll take your question at the face-vale of the title and hope you can work out anything missing from there.
If you want to do ImageMagick in bulk, you either need to use a loop in bash, like this:
#!/bin/bash
for f in *.jpg; do
convert "%f" ...
done
or use IM's mogrify command. That is quite a powerful command, so make a backup of your images before you even think of trying to use it.
Let's assume you want to place all JPEG images in the current directory onto a white 1000x1000 pixel background. You would do this:
mogrify -background white -gravity center -extent 1000x1000 *.jpg
Updated Answer
It should be possible to do the resizing and the white padding in a single ImageMagick command without needing to use SIPS as well, like this if you now want 1200x1200 square images padded with white:
mogrify -background white -gravity center -resize 1200x1200\> -extent 1200x1200 *.jpg

Remove background color in image processing for OCR

I am trying to remove background color so as to improve the accuracy of OCR against images. A sample would look like below:
I'd keep all letters in the post-processed image while just removing the light purple color textured background. Is it possible to use some open source software such as Imagemagick to convert it to a binary image (black/white) to achieve this goal? What if the background has more than one color? Would the solution be the same?
Further, what if I also want to remove the purple letters (theater name) and the line so as to only keep the black color letters? Simple cropping might not work because the purple letters could appear at other places as well.
I am looking for a solution in programming, rather than via tools like Photoshop.
You can do this using GIMP (or any other image editing tool).
Open your image
Convert to grayscale
Duplicate the layer
Apply Gaussian blur using a large kernel (10x10) to the top layer
Calculate the image difference between the top and bottom layer
Threshold the image to yield a binary image
Blurred image:
Difference image:
Binary:
If you're doing it as a once-off, GIMP is probably good enough. If you expect to do this many times over, you could probably write an imagemagick script or code up your approach using something like Python and OpenCV.
Some problems with the above approach:
The purple text (CENTURY) gets lost because it isn't as contrasting as the other text. You could work your way around it by thresholding different parts of the image differently, or by using local histogram manipulation methods
The following shows a possible strategy for processing your image, and OCR it
The last step is doing an OCR. My OCR routine is VERY basic, so I'm sure you may get better results.
The code is Mathematica code.
Not bad at all!
In Imagemagick, you can use the -lat function to do that.
convert image.jpg -colorspace gray -negate -lat 50x50+5% -negate result.jpg
convert image.jpg -colorspace HSB -channel 2 -separate +channel \
-white-threshold 35% \
-negate -lat 50x50+5% -negate \
-morphology erode octagon:1 result2.jpg
You can apply blur to the image, so you get almost clear background. Then divide each color component of each pixel of original image by the corresponding component of pixel on the background. And you will get text on white background. Additional postprocessing can help further.
This method works in the case if text is darker then the background (in each color component). Otherwise you can invert colors and apply this method.
If your image is captured as RGB, just use the green image or quickly convert the bayer pattern which is probably #misha's convert to greyscale solutions probably do.
Hope this helps someone
Using one line code you can get is using OpenCV and python
#Load image as Grayscale
im = cv2.imread('....../Downloads/Gd3oN.jpg',0)
#Use Adaptivethreshold with Gaussian
th = cv2.adaptiveThreshold(im,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
Here's the result
Here's the link for Image Thresholding in OpenCV

Resources