From 9dcbd6d93c4a8afbccac72ca5ce7108b02b08970 Mon Sep 17 00:00:00 2001 From: Frank Schumacher Date: Mon, 6 Jun 2011 22:44:26 +0200 Subject: [PATCH] Add ArcLength, ContourArea and Minimal Area Rectangle example --- .gitignore | 2 +- .../bounding-box-detect-canny.rb} | 24 ++++++++++++++++-- examples/contours/rotated-boxes.jpg | Bin 0 -> 5985 bytes examples/rotated-boxes.jpg | Bin 23702 -> 0 bytes 4 files changed, 23 insertions(+), 3 deletions(-) rename examples/{bounding-box-detect-canny-no-gui.rb => contours/bounding-box-detect-canny.rb} (56%) create mode 100644 examples/contours/rotated-boxes.jpg delete mode 100644 examples/rotated-boxes.jpg diff --git a/.gitignore b/.gitignore index 47000fd..46cb50d 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/examples/bounding-box-detect-canny-no-gui.rb b/examples/contours/bounding-box-detect-canny.rb similarity index 56% rename from examples/bounding-box-detect-canny-no-gui.rb rename to examples/contours/bounding-box-detect-canny.rb index b61158b..a475352 100755 --- a/examples/bounding-box-detect-canny-no-gui.rb +++ b/examples/contours/bounding-box-detect-canny.rb @@ -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 achor (see imagehere: 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") diff --git a/examples/contours/rotated-boxes.jpg b/examples/contours/rotated-boxes.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cf3a2e6f608fae12e59467dd8c302c3ce6902424 GIT binary patch literal 5985 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 PYWR!N@00sig|Ge>vT^Qq