Python + opencv: image outline

Machine vision 001 2020-11-16 01:29:17
python opencv image outline


Python+OpenCV: Image outline

What is the outline ?

The outline can be simply interpreted as a line connecting all the continuous points ( Along the border ) The curve of , Having the same color and intensity .

Contour lines are shape analysis 、 An important tool for target detection and recognition .

For better accuracy , You can use binary images . So before you find the outline , Threshold or... Should be applied canny edge detection .

from OpenCV 3.2 Start ,findcontour() No longer modify the source image .

stay OpenCV in , Looking for outlines is like looking for a white object from a black background . So remember , The object to be found should be white , The background should be black .

Let's see how to find the outline of a binary image :

####################################################################################################
# Image outline (Image Contours)
def lmc_cv_image_contours():
"""
The functionality : Image outline (Image Contours).
"""
# Read images
image = lmc_cv.imread('D:/99-Research/Python/Image/Box2.png')
contours_image1 = image.copy()
contours_image2 = image.copy()
gray_image = lmc_cv.cvtColor(image, lmc_cv.COLOR_BGR2GRAY)
# Image outline (Image Contours)
ret, binary_image = lmc_cv.threshold(gray_image, 127, 255, lmc_cv.THRESH_BINARY)
contours1, hierarchy1 = lmc_cv.findContours(binary_image, mode=lmc_cv.RETR_TREE, method=lmc_cv.CHAIN_APPROX_NONE,
offset=(0, 0))
contours2, hierarchy2 = lmc_cv.findContours(binary_image, mode=lmc_cv.RETR_TREE, method=lmc_cv.CHAIN_APPROX_SIMPLE,
offset=(0, 0))
lmc_cv.drawContours(contours_image1, contours1, -1, (0, 0, 255), 3)
lmc_cv.drawContours(contours_image2, contours2, -1, (0, 0, 255), 3)
points_number1 = 0
for i in range(len(contours1)):
points_number1 = points_number1 + len(contours1[i])
points_number2 = 0
for i in range(len(contours2)):
points_number2 = points_number2 + len(contours2[i])
# Display images
pyplot.figure('Image Display')
titles = ['Original Image', '%d Points in All Contours(%d)' % (points_number1, len(contours1)),
'%d Points in Simple Contours(%d)' % (points_number2, len(contours2))]
images = [image, contours_image1, contours_image2]
for i in range(3):
pyplot.subplot(1, 3, i + 1)
pyplot.imshow(images[i], 'gray')
pyplot.title(titles[i])
pyplot.xticks([])
pyplot.yticks([])
pyplot.show()
# Save images based on user input
if ord("q") == (lmc_cv.waitKey(0) & 0xFF):
# Destruction of the window
pyplot.close()
return

 

Contour feature (Contour Features)

####################################################################################################
# Image contour features (Image Contour Features)
def lmc_cv_image_contours_features():
"""
The functionality : Image contour features (Image Contour Features).
"""
# Read images
image = lmc_cv.imread('D:/99-Research/Python/Image/Box2-2.png')
contours_image1 = image.copy()
contours_image2 = image.copy()
contours_image3 = image.copy()
contours_image4 = image.copy()
contours_image5 = image.copy()
contours_image6 = image.copy()
contours_image7 = image.copy()
contours_image8 = image.copy()
gray_image = lmc_cv.cvtColor(image, lmc_cv.COLOR_BGR2GRAY)
# Image contour features (Image Contour Features)
ret, binary_image = lmc_cv.threshold(gray_image, 127, 255, lmc_cv.THRESH_BINARY)
contours, hierarchy = lmc_cv.findContours(binary_image, mode=lmc_cv.RETR_TREE, method=lmc_cv.CHAIN_APPROX_NONE,
offset=(0, 0))
points_number1 = 0
for i in range(len(contours)):
# The number of contour points
print(f" outline {i + 1} share {len(contours[i])} A little bit : ")
points_number1 = points_number1 + len(contours[i])
# Moment (Moments)
moments = lmc_cv.moments(contours[i], binaryImage=False)
print(f" outline {i + 1} Moment of : {moments}")
print(f" outline {i + 1} Centroid of x: {int(moments['m10'] / moments['m00'])}; centroid y: {int(moments['m01'] / moments['m00'])}")
# Contour area (Area)
print(f" outline {i + 1} The area of : {lmc_cv.contourArea(contours[i], oriented=False)}")
# Contour circumference (Perimeter)
perimeter = lmc_cv.arcLength(contours[i], closed=True)
print(f" outline {i + 1} The circumference of : {perimeter}")
# The outline is approximate (Contour Approximation)
approx_contour1 = lmc_cv.approxPolyDP(contours[i], epsilon=0.1 * perimeter, closed=True)
lmc_cv.drawContours(contours_image1, approx_contour1, -1, (255, 0, 0), 8)
approx_contour2 = lmc_cv.approxPolyDP(contours[i], epsilon=0.01 * perimeter, closed=True)
lmc_cv.drawContours(contours_image2, approx_contour2, -1, (0, 255, 0), 8)
# A convex outline (Convex Hull)
hull_contour = lmc_cv.convexHull(contours[i], clockwise=False, returnPoints=True)
lmc_cv.drawContours(contours_image3, hull_contour, -1, (0, 0, 255), 8)
# Profile convexity
print(f" outline {i + 1} The convexity of : {lmc_cv.isContourConvex(contours[i])}")
# No rotation boundary rectangle (Bounding Rectangle)
x, y, w, h = lmc_cv.boundingRect(contours[i])
lmc_cv.rectangle(contours_image4, (x, y), (x + w, y + h), (255, 255, 0), 4)
# There's a rotating border rectangle (Bounding Rectangle)
rect = lmc_cv.minAreaRect(contours[i])
box = lmc_cv.boxPoints(rect)
box = np.int0(box)
lmc_cv.drawContours(contours_image5, [box], 0, (0, 255, 255), 4)
# The bottom closed circle (Minimum Enclosing Circle)
(x, y), radius = lmc_cv.minEnclosingCircle(contours[i])
center = (int(x), int(y))
radius = int(radius)
lmc_cv.circle(contours_image6, center, radius, (255, 0, 255), 2)
# Fit ellipse (Fitting an Ellipse)
ellipse = lmc_cv.fitEllipse(contours[i])
lmc_cv.ellipse(contours_image7, ellipse, color=(0, 255, 0), thickness=2, lineType=lmc_cv.LINE_8)
# Fit a straight line (Fitting a Line)
rows, cols = contours_image8.shape[:2]
[vx, vy, x, y] = lmc_cv.fitLine(contours[i], lmc_cv.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((cols - x) * vy / vx) + y)
lmc_cv.line(contours_image8, (cols - 1, righty), (0, lefty), (0, 255, 0), 2)
# Display images
pyplot.figure('Image Display')
titles = ['Original Image', 'Contour Approximation 10%', 'Contour Approximation 1%', 'Convex Hull',
'Normal Bounding Rect', 'Rotated Bounding Rect', 'Minimum Enclosing Circle', 'Fitting an Ellipse',
'Fitting a Line']
images = [image, contours_image1, contours_image2, contours_image3, contours_image4, contours_image5,
contours_image6, contours_image7, contours_image8]
for i in range(9):
pyplot.subplot(3, 3, i + 1)
pyplot.imshow(images[i], 'gray')
pyplot.title(titles[i])
pyplot.xticks([])
pyplot.yticks([])
pyplot.show()
# Save images based on user input
if ord("q") == (lmc_cv.waitKey(0) & 0xFF):
# Destruction of the window
pyplot.close()
return

Convexity defect

Any deviation of the object from this hull can be considered as convexity defect.

####################################################################################################
# Image convexity defect (Image Convexity Defects)
def lmc_cv_image_convexity_defects():
"""
The functionality : Image convexity defect (Image Convexity Defects).
Any deviation between the object and the hull can be considered as a convex defect .
"""
# Read images
image = lmc_cv.imread('D:/99-Research/Python/Image/Star.png')
copy_image = image.copy()
gray_image = lmc_cv.cvtColor(image, lmc_cv.COLOR_BGR2GRAY)
# Image convexity defect (Image Convexity Defects)
ret, thresh = lmc_cv.threshold(gray_image, 127, 255, lmc_cv.THRESH_BINARY)
contours, hierarchy = lmc_cv.findContours(thresh, mode=lmc_cv.RETR_CCOMP, method=lmc_cv.CHAIN_APPROX_NONE,
offset=(0, 0))
for i in range(len(contours)):
cnt = contours[i]
print(f" spot (50, 50) The distance to the contour : {lmc_cv.pointPolygonTest(cnt, (50, 50), True)}")
print(f" spot (100, 100) The distance to the contour : {lmc_cv.pointPolygonTest(cnt, (100, 100), True)}")
print(f" spot (150, 150) The distance to the contour : {lmc_cv.pointPolygonTest(cnt, (150, 150), True)}")
hull = lmc_cv.convexHull(cnt, returnPoints=False)
defects = lmc_cv.convexityDefects(cnt, hull)
for j in range(defects.shape[0]):
s, e, f, d = defects[j, 0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
lmc_cv.line(copy_image, start, end, [0, 255, 0], 2)
lmc_cv.circle(copy_image, far, 5, [0, 0, 255], -1)
# Display images
pyplot.figure('Image Display')
titles = ['Original Image', 'Convexity Defects']
images = [image, copy_image]
for i in range(2):
pyplot.subplot(1, 2, i + 1)
pyplot.imshow(images[i], 'gray')
pyplot.title(titles[i])
pyplot.xticks([])
pyplot.yticks([])
pyplot.show()
# Save images based on user input
if ord("q") == (lmc_cv.waitKey(0) & 0xFF):
# Destruction of the window
pyplot.close()
return

Shape match (Match Shapes)

OpenCV With a function cv.matchShapes(), It allows us to compare two shapes or two outlines , And return a measure that shows similarity .

The lower the result , The better the match . It is based on Hu- Moment calculation . Different measurement methods are explained in the document .

####################################################################################################
# Image contour shape matching (Image Contours Match Shapes)
def lmc_cv_image_contour_match_shapes():
"""
The functionality : Image contour shape matching (Image Match Shapes).
OpenCV With a function cv.matchShapes(), It allows us to compare two shapes or two outlines , And return a measure that shows similarity .
The lower the result , The better the match . It is based on Hu- Moment invariance computes .
Hu- Moment is translation 、 Rotation and scaling are constant 7 Moments .
"""
# Read images
image1 = lmc_cv.imread('D:/99-Research/Python/Image/Star1.png')
image2 = lmc_cv.imread('D:/99-Research/Python/Image/Star2.png')
image3 = lmc_cv.imread('D:/99-Research/Python/Image/Box1-1.png')
gray_image1 = lmc_cv.cvtColor(image1, lmc_cv.COLOR_BGR2GRAY)
gray_image2 = lmc_cv.cvtColor(image2, lmc_cv.COLOR_BGR2GRAY)
gray_image3 = lmc_cv.cvtColor(image3, lmc_cv.COLOR_BGR2GRAY)
# Image contour shape matching (Image Match Shapes)
ret1, thresh1 = lmc_cv.threshold(gray_image1, 127, 255, lmc_cv.THRESH_BINARY)
ret2, thresh2 = lmc_cv.threshold(gray_image2, 127, 255, lmc_cv.THRESH_BINARY)
ret3, thresh3 = lmc_cv.threshold(gray_image3, 127, 255, lmc_cv.THRESH_BINARY)
contours1, hierarchy1 = lmc_cv.findContours(thresh1, mode=lmc_cv.RETR_CCOMP, method=lmc_cv.CHAIN_APPROX_NONE,
offset=(0, 0))
contours2, hierarchy2 = lmc_cv.findContours(thresh2, mode=lmc_cv.RETR_CCOMP, method=lmc_cv.CHAIN_APPROX_NONE,
offset=(0, 0))
contours3, hierarchy3 = lmc_cv.findContours(thresh3, mode=lmc_cv.RETR_CCOMP, method=lmc_cv.CHAIN_APPROX_NONE,
offset=(0, 0))
contour1 = contours1[0]
contour2 = contours2[0]
contour3 = contours3[0]
# Shape match
score1 = lmc_cv.matchShapes(contour1, contour1, method=lmc_cv.CONTOURS_MATCH_I1, parameter=0.0)
score2 = lmc_cv.matchShapes(contour1, contour2, method=lmc_cv.CONTOURS_MATCH_I1, parameter=0.0)
score3 = lmc_cv.matchShapes(contour1, contour3, method=lmc_cv.CONTOURS_MATCH_I1, parameter=0.0)
# Display images
pyplot.figure('Image Display')
titles = ['Original Image 1 Match 1 Score: %f' % score1, 'Original Image 1 Match 2 Score: %f' % score2,
'Original Image 1 Match 3 Score: %f' % score3]
images = [image1, image2, image3]
for i in range(3):
pyplot.subplot(1, 3, i + 1)
pyplot.imshow(images[i], 'gray')
pyplot.title(titles[i])
pyplot.xticks([])
pyplot.yticks([])
pyplot.show()
# Save images based on user input
if ord("q") == (lmc_cv.waitKey(0) & 0xFF):
# Destruction of the window
pyplot.close()
return

Outline hierarchy (Contours Hierarchy)

The hierarchy of contours , That is, the parent-child relationship in the outline .

theory

When we use cv.findcontour() When the function finds the outline in the image , We passed a parameter , Contour retrieval mode .

We usually use cv.RETR_LIST perhaps cv.RETR_TREE, They work well . But what exactly does that mean ?

Besides , In the output , We get three arrays , The first is the image , The second is the outline , There is also an output , We call it hierarchy .

But we've never used this hierarchy anywhere . So what is this hierarchy , What is its purpose ? What does it have to do with the function parameters mentioned earlier ?

What is the hierarchy ?

Usually we use cv.findcontour() Function to detect objects in an image , Right ? Sometimes objects are in different places . But in some cases , Some shapes are inside other shapes . It's like nesting numbers .

under these circumstances , We call the outer one as the parent node , The inner one acts as a child node . In this way , The contours in the image have a certain relationship with each other .

We can specify how a profile is connected to each other , such as , It's a sub contour of other contours , Or the father's profile , wait . The representation of this relationship is called a hierarchy .

Consider the following example :

In this image , There are some shapes , I've numbered it from 0-5.2 and 2a For the outer and inner contours of the outermost box .

here , outline 0,1,2 It's the outermost . We can say , They are hierarchy0 in , Or they're in the same hierarchylevel in .

The second is contour-2a, Think of it as contour-2 Child elements ( Or vice versa ,contour-2 yes contour-2a Parent element of ). So let it be in the hierarchy -1 in .

Similarly ,contour3 yes contour2 Child elements , It's in the next hierarchy .

Last , outline 4,5 It's the outline -3a Children of , They're on the last floor .

From the way I number the boxes , I would say contour-4 yes contour-3a The first sub element of ( It can also be contour-5).

I mention this to understand things like the same level , The outer contour , Sub contour , The outline of the father , The first sub contour and so on . Now let's go in OpenCV.

OpenCV The hierarchy in represents

Each contour has its own message , About its rank , Who is its sub contour , Who is its father's profile and so on .OpenCV Express it as an array of four values :[Next, Previous, First_Child, Parent].

Next: Represents the next contour at the same level .

for example , Take... In our graph contour-0, Who's the next contour at the same level ? yes contour-1, hold Next = 1 Write it down . Again , about Contour-1, The next one is contour-2, that Next = 2.

contour-2 Well ? There is no next outline on the same level , In short , set up Next = -1.contour-4 Well ? It is associated with contour-5 At the same level . So the next outline of it is contour5, therefore Next = 5.

Previous: The previous contour on the same contour .

ditto . Previous contour-1 The outline is on the same horizontal line contour-0. Again , For the outline -2, It's the outline -1. about contour-0, No, previous, So set it to -1.

First_Child: Represents its first sub outline .

There's no need for any explanation . about contour-2, child yes contour-2a. So it gets the outline -2a The corresponding index value .contour-3a Well ? It has two child nodes . But we only take the first sub contour , It is contour-4. therefore contour-3a Of First_Child = 4.

Parent: Represents the index of the parent contour .

It is associated with First_Child contrary . For the outline -4 And the outline -5, The father's outline is the outline -3a. For the outline -3a, It's the outline -3, And so on .

【 Be careful 】

If there is no child or parent contour , The field is treated as -1.

Contour retrieval mode (Contour Retrieval Mode)

1. RETR_LIST

This is the simplest of the four symbols ( From an explanatory point of view ). It just retrieves all the outlines , But no parent-child relationship has been created . Under this rule , Parents and children are equal , They're just outlines , That is, they all belong to the same level .

This is the simplest of the four flags (from explanation point of view). It simply retrieves all the contours, but doesn't create any parent-child relationship. Parents and kids are equal under this rule, and they are just contours. ie they all belongs to same hierarchy level.

So here, 3rd and 4th term in hierarchy array is always -1. But obviously, Next and Previous terms will have their corresponding values. Just check it yourself and verify it.

Below is the result I got, and each row is hierarchy details of corresponding contour. For eg, first row corresponds to contour 0. Next contour is contour 1. So Next = 1. There is no previous contour, so Previous = -1. And the remaining two, as told before, it is -1.

This is the good choice to use in your code, if you are not using any hierarchy features.

2. RETR_EXTERNAL

If you use this flag, it returns only extreme outer flags. All child contours are left behind. We can say, under this law, Only the eldest in every family is taken care of. It doesn't care about other members of the family :).

So, in our image, how many extreme outer contours are there? ie at hierarchy-0 level?. Only 3, ie contours 0,1,2, right? Now try to find the contours using this flag. Here also, values given to each element is same as above. Compare it with above result.

You can use this flag if you want to extract only the outer contours. It might be useful in some cases.

3. RETR_CCOMP

This flag retrieves all the contours and arranges them to a 2-level hierarchy. ie external contours of the object (ie its boundary) are placed in hierarchy-1. And the contours of holes inside object (if any) is placed in hierarchy-2. If any object inside it, its contour is placed again in hierarchy-1 only. And its hole in hierarchy-2 and so on.

Just consider the image of a "big white zero" on a black background. Outer circle of zero belongs to first hierarchy, and inner circle of zero belongs to second hierarchy.

We can explain it with a simple image. Here I have labelled the order of contours in red color and the hierarchy they belongs to, in green color (either 1 or 2). The order is same as the order OpenCV detects contours.

So consider first contour, ie contour-0. It is hierarchy-1. It has two holes, contours 1&2, and they belong to hierarchy-2. So for contour-0, Next contour in same hierarchy level is contour-3. And there is no previous one. And its first is child is contour-1 in hierarchy-2. It has no parent, because it is in hierarchy-1. So its hierarchy array is [3,-1,1,-1]

Now take contour-1. It is in hierarchy-2. Next one in same hierarchy (under the parenthood of contour-1) is contour-2. No previous one. No child, but parent is contour-0. So array is [2,-1,-1,0].

Similarly contour-2 : It is in hierarchy-2. There is not next contour in same hierarchy under contour-0. So no Next. Previous is contour-1. No child, parent is contour-0. So array is [-1,1,-1,0].

Contour - 3 : Next in hierarchy-1 is contour-5. Previous is contour-0. Child is contour-4 and no parent. So array is [5,0,4,-1].

Contour - 4 : It is in hierarchy 2 under contour-3 and it has no sibling. So no next, no previous, no child, parent is contour-3. So array is [-1,-1,-1,3].

Remaining you can fill up. 

4. RETR_TREE

And this is the final guy, Mr.Perfect. It retrieves all the contours and creates a full family hierarchy list. It even tells, who is the grandpa, father, son, grandson and even beyond... :).

For example, I took above image, rewrite the code for cv.RETR_TREE, reorder the contours as per the result given by OpenCV and analyze it. Again, red letters give the contour number and green letters give the hierarchy order.

Take contour-0 : It is in hierarchy-0. Next contour in same hierarchy is contour-7. No previous contours. Child is contour-1. And no parent. So array is [7,-1,1,-1].

Take contour-2 : It is in hierarchy-1. No contour in same level. No previous one. Child is contour-3. Parent is contour-1. So array is [-1,-1,3,1].

And remaining, try yourself.

版权声明
本文为[Machine vision 001]所创,转载请带上原文链接,感谢

  1. 利用Python爬虫获取招聘网站职位信息
  2. Using Python crawler to obtain job information of recruitment website
  3. Several highly rated Python libraries arrow, jsonpath, psutil and tenacity are recommended
  4. Python装饰器
  5. Python实现LDAP认证
  6. Python decorator
  7. Implementing LDAP authentication with Python
  8. Vscode configures Python development environment!
  9. In Python, how dare you say you can't log module? ️
  10. 我收藏的有关Python的电子书和资料
  11. python 中 lambda的一些tips
  12. python中字典的一些tips
  13. python 用生成器生成斐波那契数列
  14. python脚本转pyc踩了个坑。。。
  15. My collection of e-books and materials about Python
  16. Some tips of lambda in Python
  17. Some tips of dictionary in Python
  18. Using Python generator to generate Fibonacci sequence
  19. The conversion of Python script to PyC stepped on a pit...
  20. Python游戏开发,pygame模块,Python实现扫雷小游戏
  21. Python game development, pyGame module, python implementation of minesweeping games
  22. Python实用工具,email模块,Python实现邮件远程控制自己电脑
  23. Python utility, email module, python realizes mail remote control of its own computer
  24. 毫无头绪的自学Python,你可能连门槛都摸不到!【最佳学习路线】
  25. Python读取二进制文件代码方法解析
  26. Python字典的实现原理
  27. Without a clue, you may not even touch the threshold【 Best learning route]
  28. Parsing method of Python reading binary file code
  29. Implementation principle of Python dictionary
  30. You must know the function of pandas to parse JSON data - JSON_ normalize()
  31. Python实用案例,私人定制,Python自动化生成爱豆专属2021日历
  32. Python practical case, private customization, python automatic generation of Adu exclusive 2021 calendar
  33. 《Python实例》震惊了,用Python这么简单实现了聊天系统的脏话,广告检测
  34. "Python instance" was shocked and realized the dirty words and advertisement detection of the chat system in Python
  35. Convolutional neural network processing sequence for Python deep learning
  36. Python data structure and algorithm (1) -- enum type enum
  37. 超全大厂算法岗百问百答(推荐系统/机器学习/深度学习/C++/Spark/python)
  38. 【Python进阶】你真的明白NumPy中的ndarray吗?
  39. All questions and answers for algorithm posts of super large factories (recommended system / machine learning / deep learning / C + + / spark / Python)
  40. [advanced Python] do you really understand ndarray in numpy?
  41. 【Python进阶】Python进阶专栏栏主自述:不忘初心,砥砺前行
  42. [advanced Python] Python advanced column main readme: never forget the original intention and forge ahead
  43. python垃圾回收和缓存管理
  44. java调用Python程序
  45. java调用Python程序
  46. Python常用函数有哪些?Python基础入门课程
  47. Python garbage collection and cache management
  48. Java calling Python program
  49. Java calling Python program
  50. What functions are commonly used in Python? Introduction to Python Basics
  51. Python basic knowledge
  52. Anaconda5.2 安装 Python 库(MySQLdb)的方法
  53. Python实现对脑电数据情绪分析
  54. Anaconda 5.2 method of installing Python Library (mysqldb)
  55. Python implements emotion analysis of EEG data
  56. Master some advanced usage of Python in 30 seconds, which makes others envy it
  57. python爬取百度图片并对图片做一系列处理
  58. Python crawls Baidu pictures and does a series of processing on them
  59. python链接mysql数据库
  60. Python link MySQL database