1
0
Fork 0
mirror of https://github.com/ruby-opencv/ruby-opencv synced 2023-03-27 23:22:12 -04:00

Merge pull request #5 from thenoseman/master

Example of contours hierachies added
This commit is contained in:
ser1zw 2011-06-14 07:01:39 -07:00
commit d2ad460eb7
7 changed files with 162 additions and 3 deletions

2
.gitignore vendored
View file

@ -16,4 +16,4 @@ ext/opencv/test.txt
pkg/
log.txt
*.avi
examples/rotated-boxes-with-detected-bounding-rectangles.jpg
examples/contours/rotated-boxes-with-detected-bounding-rectangles.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -30,15 +30,35 @@ contour = canny.find_contours(:mode => OpenCV::CV_RETR_LIST, :method => OpenCV::
while contour
# No "holes" please (aka. internal contours)
unless contour.hole?
puts '-' * 80
puts "BOUNDING RECT FOUND"
puts '-' * 80
# You can detect the "bounding rectangle" which is always oriented horizontally and vertically
box = contour.bounding_rect
puts "found external contour from #{box.top_left.x},#{box.top_left.y} to #{box.bottom_right.x},#{box.bottom_right.y}"
puts "found external contour with bounding rectangle from #{box.top_left.x},#{box.top_left.y} to #{box.bottom_right.x},#{box.bottom_right.y}"
# The contour area can be computed:
puts "that contour encloses an area of #{contour.contour_area} square pixels"
# .. as can be the length of the contour
puts "that contour is #{contour.arc_length} pixels long "
# Draw that bounding rectangle
cvmat.rectangle! box.top_left, box.bottom_right, :color => OpenCV::CvColor::Black
# You can also detect the "minimal rectangle" which has an angle, width, height and center coordinates
# and is not neccessarily horizonally or vertically aligned.
# The corner of the rectangle with the lowest y and x position is the anchor (see image here: http://bit.ly/lT1XvB)
# The zero angle position is always straight up.
# Positive angle values are clockwise and negative values counter clockwise (so -60 means 60 degree counter clockwise)
box = contour.min_area_rect
puts "found minimal rectangle with its center at (#{box.center.x.round},#{box.center.y.round}), width of #{box.size.width.round}px, height of #{box.size.height.round} and an angle of #{box.angle.round} degree"
end
contour = contour.h_next
end
# And save the image
puts "Saving image with bounding rectangles"
puts "\nSaving image with bounding rectangles"
cvmat.save_image("rotated-boxes-with-detected-bounding-rectangles.jpg")

View file

@ -0,0 +1,139 @@
#!/usr/bin/env ruby
#
# This file shows the different retrieval modes for contour detection
#
require "opencv"
# Load image
# The structure of the image is "explained" in bitmap-contours-with-labels.png
cvmat = OpenCV::CvMat.load("bitmap-contours.png")
# "find_contours" does only operate on bitmap images (black/white)
mat = OpenCV::CvMat.new(cvmat.rows, cvmat.cols, :cv8u, 1)
(cvmat.rows * cvmat.cols).times do |i|
mat[i] = (cvmat[i][0] <= 128) ? OpenCV::CvScalar.new(0) : OpenCV::CvScalar.new(255)
end
# find_contours takes two parameters:
# 1. Retrieval mode (:mode, defines the structure of the contour sequence returned)
# - CV_RETR_LIST (default)
# - CV_RETR_EXTERNAL
# - CV_RETR_CCOMP
# - CV_RETR_TREE
# 2. Retrieval Method (:method, how the contours are approximated)
# - CV_CHAIN_CODE
# - CV_CHAIN_APPROX_NONE
# - CV_CHAIN_APPROX_SIMPLE (default)
# - CV_CHAIN_APPROX_TC89_L1
# - CV_CHAIN_APPROX_T89_KCOS
# - CV_LINK_RUNS
#
# The default: CV_RETR_LIST and CV_CHAIN_APPROX_SIMPLE
# This produces a flat list of contours that can be traversed with .h_next and .h_prev
#
puts "Detecting using CV_RETR_LIST and CV_CHAIN_APPROX_SIMPLE"
contour = mat.find_contours(:mode => OpenCV::CV_RETR_LIST, :method => OpenCV::CV_CHAIN_APPROX_SIMPLE)
cindex=1
while contour
puts "Contour ##{cindex} is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour = contour.h_next
cindex+=1
end
#
# CV_RETR_EXTERNAL retrieves only the outer most non "hole" contour
#
puts '-'*80
puts "Detecting using CV_RETR_EXTERNAL and CV_CHAIN_APPROX_SIMPLE"
contour = mat.find_contours(:mode => OpenCV::CV_RETR_EXTERNAL, :method => OpenCV::CV_CHAIN_APPROX_SIMPLE)
cindex=1
while contour
puts "Contour ##{cindex} is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour = contour.h_next
cindex+=1
end
#
# CV_RETR_CCOMP organizes the contours in a two level deep stack
# The first level holds the contours
# The second level contains the holes of the contours in level 1
#
# C00001 <-> C00000 <-> C000 <-> C0
# | |
# V V
# H0000 H00
#
puts '-'*80
puts "Detecting using CV_RETR_CCOMP and CV_CHAIN_APPROX_SIMPLE"
contour = mat.find_contours(:mode => OpenCV::CV_RETR_CCOMP, :method => OpenCV::CV_CHAIN_APPROX_SIMPLE)
# C00001
puts "Contour #1 is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour = contour.h_next
# C00000
puts "Contour #2 is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour = contour.h_next
# C000
puts "Contour #3 is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour_down = contour.v_next
# H0000
puts "Contour #4 is #{contour_down.contour_area} px^2 (width: #{contour_down.bounding_rect.width}, height: #{contour_down.bounding_rect.height}, type: #{(contour_down.hole?)?"hole":"contour"})"
contour = contour.h_next
# C0
puts "Contour #5 is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour_down = contour.v_next
# H00
puts "Contour #6 is #{contour_down.contour_area} px^2 (width: #{contour_down.bounding_rect.width}, height: #{contour_down.bounding_rect.height}, type: #{(contour_down.hole?)?"hole":"contour"})"
#
# CV_RETR_TREE manages the contours in a tree structure
# This reconstructs the complete hierarchy of contours and holes that the image displayed
#
# C0
# |
# V
# H00
# |
# V
# C000
# |
# V
# H0000-------+
# | |
# V V
# C00000 C00001
#
puts '-'*80
puts "Detecting using CV_RETR_TREE and CV_CHAIN_APPROX_SIMPLE"
contour = mat.find_contours(:mode => OpenCV::CV_RETR_TREE, :method => OpenCV::CV_CHAIN_APPROX_SIMPLE)
# C0
puts "Contour #1 is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour = contour.v_next
# H00
puts "Contour #2 is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour = contour.v_next
# C000
puts "Contour #3 is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour = contour.v_next
# H0000
puts "Contour #4 is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour = contour.v_next
# C00000
puts "Contour #5 is #{contour.contour_area} px^2 (width: #{contour.bounding_rect.width}, height: #{contour.bounding_rect.height}, type: #{(contour.hole?)?"hole":"contour"})"
contour_right = contour.h_next
# C00001
puts "Contour #6 is #{contour_right.contour_area} px^2 (width: #{contour_right.bounding_rect.width}, height: #{contour_right.bounding_rect.height}, type: #{(contour_right.hole?)?"hole":"contour"})"

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB