init - 初始化项目
This commit is contained in:
234
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines1.svg
Normal file
234
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines1.svg
Normal file
@@ -0,0 +1,234 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="177.16013"
|
||||
height="162.30061"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="houghline1.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<inkscape:path-effect
|
||||
effect="skeletal"
|
||||
id="path-effect8912"
|
||||
is_visible="true"
|
||||
pattern="M 0,0 1,0"
|
||||
copytype="single_stretched"
|
||||
prop_scale="1"
|
||||
scale_y_rel="false"
|
||||
spacing="0"
|
||||
normal_offset="0"
|
||||
tang_offset="0"
|
||||
prop_units="false"
|
||||
vertical_pattern="false"
|
||||
fuse_tolerance="0" />
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Send"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Send"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3774"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
|
||||
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<inkscape:path-effect
|
||||
effect="skeletal"
|
||||
id="path-effect7919"
|
||||
is_visible="true"
|
||||
pattern="m -1.0101525,-0.75761441 0.99999995,0"
|
||||
copytype="single_stretched"
|
||||
prop_scale="1"
|
||||
scale_y_rel="false"
|
||||
spacing="0"
|
||||
normal_offset="0"
|
||||
tang_offset="0"
|
||||
prop_units="false"
|
||||
vertical_pattern="false"
|
||||
fuse_tolerance="0" />
|
||||
<linearGradient
|
||||
id="linearGradient7535"
|
||||
osb:paint="solid">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop7537" />
|
||||
</linearGradient>
|
||||
<inkscape:path-effect
|
||||
effect="skeletal"
|
||||
id="path-effect6087"
|
||||
is_visible="true"
|
||||
pattern="m -18.94036,-2.5253814 1,0"
|
||||
copytype="single_stretched"
|
||||
prop_scale="1"
|
||||
scale_y_rel="false"
|
||||
spacing="0"
|
||||
normal_offset="0"
|
||||
tang_offset="0"
|
||||
prop_units="false"
|
||||
vertical_pattern="false"
|
||||
fuse_tolerance="0" />
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3765"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3768"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Lend"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3762"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
|
||||
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Lstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow2Lstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3777"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="matrix(1.1,0,0,1.1,1.1,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.2"
|
||||
inkscape:cx="52.657337"
|
||||
inkscape:cy="137.18191"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="10"
|
||||
fit-margin-left="10"
|
||||
fit-margin-right="5"
|
||||
fit-margin-bottom="5"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="709"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-179.63266,-391.69653)">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.7592535px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
|
||||
d="m 350.84372,403.40485 -159.50274,0 0,144.64323"
|
||||
id="path2985"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 313.14729,416.97623 207.33381,522.78971"
|
||||
id="path5321"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3, 1;stroke-dashoffset:0;marker-start:none;marker-end:none"
|
||||
d="M 191.17137,403.33917 259.2304,471.3982"
|
||||
id="path5323"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 264.65997,465.46355 -7.95495,-7.95495 -5.93465,5.93465"
|
||||
id="path5701"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.18746948px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="222.84058"
|
||||
y="431.17072"
|
||||
id="text8491"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="scale(0.95341781,1.0488581)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan8493"
|
||||
x="222.84058"
|
||||
y="431.17072">ρ</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:11.58907604px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="241.60213"
|
||||
y="356.61414"
|
||||
id="text8495"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="scale(0.8575127,1.1661635)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan8497"
|
||||
x="241.60213"
|
||||
y="356.61414">θ</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.46696162;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
|
||||
d="m 205.18489,403.44491 c -0.0814,1.73816 0.44467,3.57132 -0.24208,5.17013 -0.64958,1.51228 -2.24971,2.34519 -3.3891,3.53293"
|
||||
id="path8910"
|
||||
inkscape:path-effect="#path-effect8912"
|
||||
inkscape:original-d="m 205.18489,403.44491 c -0.0807,1.72338 0.43883,3.58492 -0.24208,5.17013 -0.64405,1.49942 -2.2594,2.35529 -3.3891,3.53293"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cac" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
BIN
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines2.jpg
Normal file
BIN
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
BIN
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines3.jpg
Normal file
BIN
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
BIN
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines4.png
Normal file
BIN
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines5.jpg
Normal file
BIN
doc/py_tutorials/py_imgproc/py_houghlines/images/houghlines5.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
108
doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.markdown
Normal file
108
doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.markdown
Normal file
@@ -0,0 +1,108 @@
|
||||
Hough Line Transform {#tutorial_py_houghlines}
|
||||
====================
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this chapter,
|
||||
- We will understand the concept of the Hough Transform.
|
||||
- We will see how to use it to detect lines in an image.
|
||||
- We will see the following functions: **cv.HoughLines()**, **cv.HoughLinesP()**
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
The Hough Transform is a popular technique to detect any shape, if you can represent that shape in a
|
||||
mathematical form. It can detect the shape even if it is broken or distorted a little bit. We will
|
||||
see how it works for a line.
|
||||
|
||||
A line can be represented as \f$y = mx+c\f$ or in a parametric form, as
|
||||
\f$\rho = x \cos \theta + y \sin \theta\f$ where \f$\rho\f$ is the perpendicular distance from the origin to the
|
||||
line, and \f$\theta\f$ is the angle formed by this perpendicular line and the horizontal axis measured in
|
||||
counter-clockwise (That direction varies on how you represent the coordinate system. This
|
||||
representation is used in OpenCV). Check the image below:
|
||||
|
||||

|
||||
|
||||
So if the line is passing below the origin, it will have a positive rho and an angle less than 180. If it
|
||||
is going above the origin, instead of taking an angle greater than 180, the angle is taken less than 180,
|
||||
and rho is taken negative. Any vertical line will have 0 degree and horizontal lines will have 90
|
||||
degree.
|
||||
|
||||
Now let's see how the Hough Transform works for lines. Any line can be represented in these two terms,
|
||||
\f$(\rho, \theta)\f$. So first it creates a 2D array or accumulator (to hold the values of the two parameters)
|
||||
and it is set to 0 initially. Let rows denote the \f$\rho\f$ and columns denote the \f$\theta\f$. Size of
|
||||
array depends on the accuracy you need. Suppose you want the accuracy of angles to be 1 degree, you will
|
||||
need 180 columns. For \f$\rho\f$, the maximum distance possible is the diagonal length of the image. So
|
||||
taking one pixel accuracy, the number of rows can be the diagonal length of the image.
|
||||
|
||||
Consider a 100x100 image with a horizontal line at the middle. Take the first point of the line. You
|
||||
know its (x,y) values. Now in the line equation, put the values \f$\theta = 0,1,2,....,180\f$ and check
|
||||
the \f$\rho\f$ you get. For every \f$(\rho, \theta)\f$ pair, you increment value by one in our accumulator
|
||||
in its corresponding \f$(\rho, \theta)\f$ cells. So now in accumulator, the cell (50,90) = 1 along with
|
||||
some other cells.
|
||||
|
||||
Now take the second point on the line. Do the same as above. Increment the values in the cells
|
||||
corresponding to `(rho, theta)` you got. This time, the cell (50,90) = 2. What you actually
|
||||
do is voting the \f$(\rho, \theta)\f$ values. You continue this process for every point on the line. At
|
||||
each point, the cell (50,90) will be incremented or voted up, while other cells may or may not be
|
||||
voted up. This way, at the end, the cell (50,90) will have maximum votes. So if you search the
|
||||
accumulator for maximum votes, you get the value (50,90) which says, there is a line in this image
|
||||
at a distance 50 from the origin and at angle 90 degrees. It is well shown in the below animation (Image
|
||||
Courtesy: [Amos Storkey](http://homepages.inf.ed.ac.uk/amos/hough.html) )
|
||||
|
||||

|
||||
|
||||
This is how hough transform works for lines. It is simple, and may be you can implement it using
|
||||
Numpy on your own. Below is an image which shows the accumulator. Bright spots at some locations
|
||||
denote they are the parameters of possible lines in the image. (Image courtesy: [Wikipedia](http://en.wikipedia.org/wiki/Hough_transform) )
|
||||
|
||||

|
||||
|
||||
Hough Transform in OpenCV
|
||||
=========================
|
||||
|
||||
Everything explained above is encapsulated in the OpenCV function, **cv.HoughLines()**. It simply returns an array of :math:(rho,
|
||||
theta)\` values. \f$\rho\f$ is measured in pixels and \f$\theta\f$ is measured in radians. First parameter,
|
||||
Input image should be a binary image, so apply threshold or use canny edge detection before
|
||||
applying hough transform. Second and third parameters are \f$\rho\f$ and \f$\theta\f$ accuracies
|
||||
respectively. Fourth argument is the threshold, which means the minimum vote it should get to be
|
||||
considered as a line. Remember, number of votes depends upon the number of points on the line. So it
|
||||
represents the minimum length of line that should be detected.
|
||||
@include hough_line_transform.py
|
||||
Check the results below:
|
||||
|
||||

|
||||
|
||||
Probabilistic Hough Transform
|
||||
-----------------------------
|
||||
|
||||
In the hough transform, you can see that even for a line with two arguments, it takes a lot of
|
||||
computation. Probabilistic Hough Transform is an optimization of the Hough Transform we saw. It doesn't
|
||||
take all the points into consideration. Instead, it takes only a random subset of points which is
|
||||
sufficient for line detection. We just have to decrease the threshold. See image below which compares
|
||||
Hough Transform and Probabilistic Hough Transform in Hough space. (Image Courtesy :
|
||||
[Franck Bettinger's home page](http://phdfb1.free.fr/robot/mscthesis/node14.html) )
|
||||
|
||||

|
||||
|
||||
OpenCV implementation is based on Robust Detection of Lines Using the Progressive Probabilistic
|
||||
Hough Transform by Matas, J. and Galambos, C. and Kittler, J.V. @cite Matas00. The function used is
|
||||
**cv.HoughLinesP()**. It has two new arguments.
|
||||
- **minLineLength** - Minimum length of line. Line segments shorter than this are rejected.
|
||||
- **maxLineGap** - Maximum allowed gap between line segments to treat them as a single line.
|
||||
|
||||
Best thing is that, it directly returns the two endpoints of lines. In previous case, you got only
|
||||
the parameters of lines, and you had to find all the points. Here, everything is direct and simple.
|
||||
@include probabilistic_hough_line_transform.py
|
||||
See the results below:
|
||||
|
||||

|
||||
|
||||
Additional Resources
|
||||
--------------------
|
||||
|
||||
-# [Hough Transform on Wikipedia](http://en.wikipedia.org/wiki/Hough_transform)
|
||||
|
||||
Exercises
|
||||
---------
|
||||
Reference in New Issue
Block a user