Explanation of hough transform for ImageMagick - imagemagick

Preview:
I have done a hough line detection using the below mentioned code:
convert image.jpg -threshold 90% -canny 0x1+10%+30% \
\( +clone -background none \
-fill red -stroke red -strokewidth 2 \
-hough-lines 5x5+80 -write lines.mvg \
\) -composite hough.png
And I wrote the details of the line in a .mvg file. the .mvg file contents are as shown below:
# Hough line transform: 5x5+80
viewbox 0 0 640 360
line 448.256,0 473.43,360 # 104
line 0,74.5652 640,29.8121 # 158
line 0,289.088 640,244.335 # 156
line 0,292.095 640,247.342 # 133
line 154.541,0 179.714,360 # 125
line 151.533,0 176.707,360 # 145
And check here the output hough.png file.
Problem:
What does #104, #158, #156... stands for, I guess they are line numbers. If so why they are numbered in such a way?
Also I would like to know how the co-ordinates has been assigned.
It will be really helpful if I can get an explanation for the contents in .mvg file.

The # <number> is the maxima value. It defaults to count, which is set by line_count, and in returned influenced by threshold you specified. The number will decrease if the matrix element count is greater than previous height/width iteration. So... If you give it a threshold of -hough-lines 5x5+80, then line 448.256,0 473.43,360 # 104 was found about 24 pixels(or lines?) past the threshold. The next iteration would drop the maxima below the 80 threashold, so we stop comparing the matrix elements.
Also I would like to know how the co-ordinates has been assigned.
I can only answer this by pseudo-quoting the source code, but it's basic trigonometry.
if ((x >= 45) %% (x <= 135)) {
y = (r-x cos(t))/sin(t)
else {
x = (r-y cos(t))/sin(t)
}
where r is defined as y - midpoint element matrix height
where t is defined as x + midpoint rows
Find out more in the HoughLineImage method located in feature.c

Related

ImageMagick: How to extract tiles in a grid from a single PNG?

I know questions like this get asked a lot, but I haven't been able to find an answer to my specific use-case.
I frequently have to extract rectangular tile images that are laid out in a grid in a single PNG. The image contains a grid of M x N tiles. The upper-left corner of the upper-left tile in the grid is at offset (X, Y) in pixels. Each tile is WxH pixels in size. In addition, each tile in a row is DX pixels from upper-left corner to upper-left corner (so that DX >= W), and each column is DY pixels below the one above it (DY >= H).
In this picture, M=3 and N=2
Give all these variables, could someone please tell me what command to use to extract the six tiles into their own PNG files? I'm assuming it's using the 'convert' command.
Thanks.
There is no simple crop command in Imagemagick that will do the offset tile cropping. But you can do that with a combination of 3 crop commands.
Crop the larger area that you want from the image
Tile crop with no skip
Crop each tile to remove the skip area
Input:
Here I make an animation simply for demonstration. Use PNG output or JPG output for separate tiles.
convert -delay 50 lena.png \
-crop 200x200+20+20 +repage \
-crop 100x100 +repage \
-crop 90x90+0+0 +repage \
-loop 0 lena_crop.gif
I was able to get this working using the following script:
#!/bin/bash
COLS=8
ROWS=4
WIDTH=263
HEIGHT=500
XOFF=154
YOFF=176
DX=267
DY=523
IMAGE=image
mkdir -p ${IMAGE}
for M in `seq 0 $(($COLS - 1))`
do
for N in `seq 0 $(($ROWS - 1))`
do
X=$(($XOFF + $M * $DX))
Y=$(($YOFF + $N * $DY))
convert ${IMAGE}.png[${WIDTH}x${HEIGHT}+${X}+${Y}] ${IMAGE}/${IMAGE}-${M}-${N}.png
done
done
I'm not sure how elegant this is.

ImageMagick - Trim / Crop to contiguous objects

How do you do the equivalent of this step in Photoshop.
https://gyazo.com/180a507c0f3c9b342fe33ce218cd512e
Supposed there are two contiguous objects in an image, and you want to create exact sized crops around each one and output as two files. (Generalize to N files)
You can do that with "Connected Component Analysis" to find the contiguous blobs.
Start Image
convert shapes.png -colorspace gray -negate -threshold 10% \
-define connected-components:verbose=true \
-connected-components 8 -normalize output.png
Sample Output
Objects (id: bounding-box centroid area mean-color):
0: 416x310+0+0 212.3,145.2 76702 srgb(0,0,0)
1: 141x215+20+31 90.0,146.2 26129 srgb(255,255,255)
2: 141x215+241+75 311.0,190.2 26129 srgb(255,255,255)
Notice how each blob, or contiguous object, is "labelled" or identified with its own unique colour (shade of grey).
So there is a header line telling you what the fields are followed by 3 blobs, i.e. one per line of output. The first line is the entire image and not much use. The second one is 141 px wide and 215 px tall starting at +20+31 from the top-left corner. The third one is the same size (because I copied the shape) and starts as +241+75 from the top-left corner.
Now stroke red around the final indicated rectangle - bearing in mind that rectangle takes top-left and bottom-right corners rather than top-left corner plus width and height.
convert shapes.png -stroke red -fill none -draw "rectangle 241,75 382,290" z.png
And crop it:
convert shapes.png -crop 141x215+241+75 z.png
And here is the extracted part:
If you want to generalise, you can just pipe the ImageMagick output into awk and pick out the geometry field:
convert shapes.png -colorspace gray -negate -threshold 10% -define connected-components:verbose=true -connected-components 8 -normalize output.png | awk 'NR>2{print $2}'
Sample Output
141x215+20+31
141x215+241+75

Detecting square size on a grid

I need to detect the size of a square on a grid like this one (all squares are supposed to be equal):
http://imgur.com/VZAimWS
I could think of many different strategies to find out what is the length of a side of a square, but I would expect there might be a particular technique that is more robust or considered better in terms of providing a more accurate answer. Any tips? One of the things I was exploring is to identify each parallel line and find the average (or maybe median) distance between the lines.
In case it's relevant, I am planning to use MatLab or OpenCV for this.
Thank you
I see you want to do this in Matlab, but you might get some inspiration from my attacking it with ImageMagick, which is installed on most Linux distros, and available for OS X and Windows for free from here.
Here is the bones of how I proceed - it's just one command in the Terminal - no compilers, no OpenCV, no Matlab:
convert grid.jpg \
-threshold 80% -negate \
-morphology Thinning:-1 Skeleton \
\( +clone \
-background none \
-fill red -stroke red -strokewidth 2 \
-hough-lines 9x9+150 -write lines.mvg \
\) \
-composite hough.png
That lovely command, does these steps:
thresholds the image to black and white at 80%
inverts it
thins it to a skeleton
copies the whole lot and on the copy performs a Hough Line detection colouring the lines in red
overlays the detected lines back onto the original image
The output image is like this:
And the file lines.mvg contains the line coordinates on which the maths is needed...
# Hough line transform: 9x9+150
viewbox 0 0 1777 1449
line 177.944,0 102.005,1449 # 191 <-- shown in yellow below
line 171.848,0 121.248,1449 # 332
line 0,118.401 1777,149.419 # 453
line 0,143 1777,143 # 181
line 0,283.426 1777,314.444 # 431
line 504.586,0 479.293,1449 # 252
line 0,454.452 1777,485.47 # 403
line 0,481 1777,481 # 164
line 0,627.479 1777,658.496 # 309
line 0,649 1777,649 # 233
line 842.637,0 817.345,1449 # 299
line 0,801.505 1777,832.523 # 558
line 0,844.525 1777,813.507 # 167
line 0,973.531 1777,1004.55 # 291
line 0,1013.55 1777,982.533 # 158
line 1180.69,0 1155.4,1449 # 495
line 0,1146.56 1777,1177.58 # 396
line 0,1182.58 1777,1151.56 # 350
line 0,1331 1777,1331 # 320
line 1510.74,0 1485.45,1449 # 539
line 0,1352.6 1777,1321.58 # 277
line 1504,0 1504,1449 # 201
I'll draw the first line from the list above in on the image in yellow so you can see how the coordinates work.
convert hough.png -stroke yellow -draw "line 177.944,0 102.005,1449" out.jpg
Now, about that maths... it is going to be hard to measure correctly on a distorted image, because it's... well, distorted. I would think about 2 strategies. Either take the top line and solve for its intersection with the leftmost line, and the same in the other 3 corners, You can then calculate the two diagonals of the image and estimate the distortion and amortize it across lots of squares which may be good. Or you could solve for the intersections of all the lines and apply some type of clustering to eradicate multiply-defined corners... or something simpler altogether.
Let's look at just the vertical lines...
grep -v "line 0" lines.mvg
line 177.944,0 102.005,1449 # 191
line 171.848,0 121.248,1449 # 332
line 504.586,0 479.293,1449 # 252
line 842.637,0 817.345,1449 # 299
line 1180.69,0 1155.4,1449 # 495
line 1510.74,0 1485.45,1449 # 539
line 1504,0 1504,1449 # 201
The first two are the same line, so let's average 177 and 171 to give 174. The last two are also the same line, so if we average 1510 and 1504 we get 1507. So, now the grid spacings are
330px = 504-174
338px = 842-504
338px = 1180-842
357px = 1507-1180
So, I'm going for 338px... ish :-)
Well what I would try is:
Pass a threshold and you will get a better edge of the squares.
Then pass the HoughLines algorithm
You will get lines, please adapt the configuration to the best performance in order to see all the lines.
Calculate the points where every line cross with another line and you will have the vertexes of each one.
Use a little math! :)

ImageMagick Convert not generating correct color

When I run this command:
convert -units PixelsPerCentimeter -type TrueColorMatte -channel RGBA -size 32x32 -alpha transparent xc:none -fill "hsla(60 ,83% ,64%)" -draw "circle 15,16 8,10" png32:"/test.png"
I am getting an image with a color of hsla(215,79%,64%,1) instead of hsla(60, 83%, 64%, 1) as specified in the fill argument, am I doing anything wrong?
I am running Mac OS X 10.9 and ImageMagick 6.8.7-7 Q16 x86_64 2013-11-27
I have tried simplifying your command and re-running it on my OSX Mavericks to see what gives. Basically, I found I could safely remove several things and it made no difference, till I got down to this which still gives the same result as your example (I think):
convert -size 32x32 xc:transparent -fill "hsla(60 ,83% ,64%,1)" -draw "circle 15,16 8,10" png32:a.png
Then I thought about the ranges for each of H, S and L. The range for H is 0-360, and then I realised that your 60 for H is being interpreted as 60% because, with a little rounding error, 60*360/100=215 which is what you are seeing for your H value. So, I changed your H value from 60 to 16 (since 16% of 360 is the 60 you want) and it comes out as the 60 you wanted. Not sure if it is a bug, or what, but I think that is what is happening.
By the way, I note that Fred, on this page, is careful never to mix pure numbers with percentages when specifying HSL colours, so maybe his software doesn't expect us to either...
I am now certain that IM is interpreting your H value as a percentage, if you put in 50, you get out 180 (50% of 360) and if you put in 10, you get out 36 (10% of 360).

Understanding Perspective Projection Distortion ImageMagick

For a project I am trying to create a perspective distortion of an image to match a DVD case front template. So I want to automate this using ImageMagick (CLI) but I have a hard time understanding the mathematical aspects of this transformation.
convert \
-verbose mw2.png \
-alpha set \
-virtual-pixel transparent \
-distort Perspective-Projection '0,0 0,0 0,0 0,0' \
box.png
This code is en empty set of coordinates, I have read the documentation thoroughly but I can't seem to understand what parameter represents what point. The documentation gives me variables and names where I have no clue what they actually mean (more useful for a mathematical mastermind maybe). So if someone could explain me (visually prefered, or give me a link to useful information) on this subject because I have no clue on what I am doing. Just playing around with the parameters just wont do for this job and I need to calculate these points.
Here you will find an easy image of what I am trying to achieve (with CLI tools):
Update:
convert \
-virtual-pixel transparent \
-size 159x92 \
-verbose \
cd_empty.png \
\(mw2.png -distort Perspective '7,40 4,30 4,124 4,123 85,122 100,123 85,2 100,30'\) \
-geometry +3+20 \
-composite cover-after.png
Gives me as output:
cd_empty.png PNG 92x159 92x159+0+0 8-bit sRGB 16.1KB 0.000u 0:00.000
convert: unable to open image `(mw2.png': No such file or directory # error/blob.c/OpenBlob/2641.
convert: unable to open file `(mw2.png' # error/png.c/ReadPNGImage/3741.
convert: invalid argument for option Perspective : 'require at least 4 CPs' # error/distort.c/GenerateCoefficients/807.
convert: no images defined `cover-after.png' # error/convert.c/ConvertImageCommand/3044.
Correction by Kurt Pfeifle:
The command has a syntax error, because it does not surround the \( and \) delimiters by (at least one) blank on each side as required by ImageMagick!
Since there are no links to the source images provided, I cannot test the outcome of this corrected command:
convert \
-virtual-pixel transparent \
-size 159x92 \
-verbose \
cd_empty.png \
\( \
mw2.png -distort Perspective '7,40 4,30 4,124 4,123 85,122 100,123 85,2 100,30' \
\) \
-geometry +3+20 \
-composite \
cover-after.png
Did you see this very detailed explanation of ImageMagick's distortion algorithms? It comes with quite a few illustrations as well.
From looking at your example image, my guess is that you'll get there using a Four Point Distortion Method.
Of course, the example you gave with the 0,0 0,0 0,0 0,0 parameter does not do what you want.
Many of the distortion methods available in ImageMagick work like this:
The method uses a set of pairs of control points.
The values are numbers (may be floating point, not only integer).
Each pair of control points represents a pixel coordinate.
Each set of four values represent a source image coordinate, followed immediately by the destination image coordinate.
Transfer the coordinates for each source image control point into the respective destination image control point exactly as given by the respective parameters.
Transfer all the other pixel's coordinates according to the distortion method given.
Example:
Sx1,Sy1 Dx1,Dy1
Sx2,Sy2 Dx2,Dy2
Sx3,Sy3 Dx3,Dy3
...
Sxn,Syn Dxn,Dyn
x is used to represent an X coordinate.
y is used to represent an Y coordinate.
1, 2, 3, ... n is used to represent the 1st, 2nd, 3rd, ... nth pixel.
S is used here for the source pixel.
D is used here for the destination pixel.
First: method -distort perspective
The distortion method perspective will make sure that straight lines in the source image will remain straight lines in the destination image. Other methods, like barrel or bilinearforward do not: they will distort straight lines into curves.
The -distort perspective requires a set of at least 4 pre-calculated pairs of pixel coordinates (where the last one may be zero). More than 4 pairs of pixel coordinates provide for more accurate distortions. So if you used for example:
-distort perspective '1,2 3,4 5,6 7,8 9,10 11,12 13,14 15,16'
(for readability reasons using more {optional} blanks between the mapping pairs than required) would mean:
From the source image take pixel at coordinate (1,2) and paint it at coordinate (3,4) in the destination image.
From the source image take pixel at coordinate (5,6) and paint it at coordinate (7,8) in the destination image.
From the source image take pixel at coordinate (9,10) and paint it at coordinate (11,12) in the destination image.
From the source image take pixel at coordinate (13,14) and paint it at coordinate (15,16) in the destination image.
You may have seen photo images where the vertical lines (like the corners of building walls) do not look vertical at all (due to some tilting of the camera when taking the snap). The method -distort perspective can rectify this.
It can even achieve things like this, 'straightening' or 'rectifying' one face of a building that appears in the 'correct' perspective of the original photo:
==>
The control points used for this distortion are indicated by the corners of the red (source controls) and blue rectangles (destination controls) drawn over the original image:
==>
This particular distortion used
-distort perspective '7,40 4,30 4,124 4,123 85,122 100,123 85,2 100,30'
Complete command for your copy'n'paste pleasure:
convert \
-verbose \
http://i.stack.imgur.com/SN7sm.jpg \
-matte \
-virtual-pixel transparent \
-distort perspective '7,40 4,30 4,124 4,123 85,122 100,123 85,2 100,30' \
output.png
Second: method -distort perspective-projection
The method -distort perspective-projection is derived from the easier understandable perspective method. It achieves the exactly same distortion result as -distort perspective does, but doesn't use (at least) 4 pairs of coordinate values (at least 16 integers) as parameter, but 8 floating point coefficients.
It uses...
A set of exactly 8 pre-calculated coefficients;
Each of these coefficients is a floating point value (unlike with -distort perspective, where for values only integers are allowed);
These 8 values represent a matrix of the form
sx ry tx
rx sy ty
px py
which is used to calculate the destination pixels from the source pixels according to this formula:
X-of-destination = (sx*xs + ry+ys +tx) / (px*xs + py*ys +1)
Y-of-destination = (rx*xs + sy+ys +ty) / (px*xs + py*ys +1)
(TO BE DONE --
I've no time right now to find out how to
properly format + put formulas into the SO editor)
To avoid (the more difficult) calculating of the 8 required cooefficients for a re-usable -distort perspective-projection method, you can...
FIRST, (more easily) calculate the coordinates for a -distort perspective ,
SECOND, run this -distort perspective with a -verbose parameter added,
LAST, read the 8 coefficients from the output printed to stderr .
The (above quoted) complete command example would spit out this info:
Perspective Projection:
-distort PerspectiveProjection \
'1.945622, 0.071451, -12.187838, 0.799032,
1.276214, -24.470275, 0.006258, 0.000715'
Thanks to ImageMagick Distorting Images Documentation, I ended up with this clean-understandable code:
$points = array(
0,0, # Source Top Left
0,0, # Destination Top Left
0,490, # Source Bottom Left
2.2,512, # Destination Bottom Left
490,838, # Source Bottom Right
490,768, # Destination Bottom Right
838,0, # Source Top Right
838,50 # Destination Top Right
);
$imagick->distortImage(Imagick::DISTORTION_PERSPECTIVE, $points, false);
Please keep in mind that each set of coordinates are separated into two
parts. The first is the X axis and the second is the Y axis .. so when we say 838,0
at Destination Right Top, we mean the X axis of Destination Right Top
is 838 and the Y axis of it is zero (0).

Resources