'The contour detected using opencv to dxf

I used opencv to detect contours in Python. I wrote the code for saving this contour as a dxf file as below through a search.

cap = EasyPySpin.VideoCapture(0)

_, frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
frame = cv2.resize(frame, dsize=(0,0), fx=0.26, fy=0.26, interpolation=cv2.INTER_AREA)
frame_blr = cv2.GaussianBlur(frame, (3, 3), 0)  
canny = cv2.Canny(frame_blr, 255, 0)
contours, hierarchy=cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours_draw = cv2.drawContours(frame, contours, -1, (0, 255, 0), 1)
cv2.imshow('contour', contours_draw)


contours = [np.squeeze (cnt, axis = 1) for cnt in contours]
ctr = contours[1]
dwg = ezdxf.new ('R2010') # create a new DXF R2010 drawing, official DXF version name: 'AC1024'
msp = dwg.modelspace () # add new entities to the model space
dwg.layers.new (name = 'MyLines', dxfattribs = {'color': 3}) # 3 = Green


for i in range (len (ctr)):
    n = i + 1
    if n>= len (ctr):
        n = 0
    msp.add_line (ctr [i], ctr [n], dxfattribs = {'layer': 'MyLines'}) # add a LINE entity
    print (ctr [i], '->', ctr [n])
dwg.saveas ('line.dxf')

But the detected contour and the line drawn in the dxf file are different. Also, a slightly different line is drawn in the dxf file every time it runs.I don't know why.

Contour Image > enter image description here DXF file > enter image description here

And I don't know what this code means.

contours = [np.squeeze (cnt, axis = 1) for cnt in contours]
ctr = contours[1]

If I delete this code and edit the crt into contours, the following error occurs.

Traceback (most recent call last):
  File "c:/Users/MyPc/KHS/p40.contour detection, (x,y).py", line 38, in <module>
    msp.add_line (contours [i], contours [n], dxfattribs = {'layer': 'MyLines'}) # add a LINE entity
  File "C:\Users\MyPc\AppData\Local\Programs\Python\Python38\lib\site-packages\ezdxf\graphicsfactory.py", line 121, in add_line
    dxfattribs["start"] = Vec3(start)
  File "src\ezdxf\acc\vector.pyx", line 417, in ezdxf.acc.vector.Vec3.__cinit__
TypeError: invalid argument count


Solution 1:[1]

Setup

>>> import cv2
... import numpy as np
... frame = cv2.imread("cyan quick_3_MAD.png")

>>> canny = cv2.Canny(frame, 255, 0)
>>> contours, hierarchy = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
>>> contours_draw = cv2.drawContours(frame, contours, -1, (0, 255, 0), 1)

>>> cv2.imwrite("out.png", contours_draw)

output:

contour


What is np.squeeze?

For this example, contours looks like this:

>>> print(str(contours)[:400])
[array([[[629, 568]],

       [[629, 569]],

       [[629, 570]],
       ...


>>> len(contours)
188

>>> contours[0].shape
(59, 1, 2)

After using np.squeeze, unnecessary 1-sized axis is removed.

squeezed = [np.squeeze(cnt, axis=1) for cnt in contours]

>>> len(squeezed)
188

>>> squeezed[0].shape
(59, 2)

To quote from document np.squeeze

numpy.squeeze(a, axis=None)
Remove axes of length one from a.


Critical part

You used ctr = contours[1], which means you Only draw first contour in list among multiple contours.

Instead, you need to iterate thru contours and draw every contour it has.

>>> import ezdxf
... dwg = ezdxf.new("R2010")
... msp = dwg.modelspace()
... dwg.layers.new(name="greeny green lines", dxfattribs={"color": 3})

>>> for ctr in squeezed:
...     for n in range(len(ctr)):
...         if n >= len(ctr) - 1:
...             n = 0
...         try:
...             msp.add_line(ctr[n], ctr[n + 1], dxfattribs={"layer": "greeny green lines", "lineweight": 20})
...         except IndexError:
...             pass

>>> dwg.saveas("output.dxf")

output:

enter image description here


Update

To flip the image, we can just simply invert y values.

Since squeezed was list of np arrays that contains countours, we can simply multiply vector [1, -1] to it to flip values in y axis.

>>> inverted_squeezed = [arr * [1, -1] for arr in squeezed]

>>> for ctr in inverted_squeezed:
...     for n in range(len(ctr)):
...         if n >= len(ctr) - 1:
...             n = 0
...         try:
...             msp.add_line(ctr[n], ctr[n + 1], dxfattribs={"layer": "greeny green lines", "lineweight": 20})
...         except IndexError:
...             pass

>>> dwg.saveas("output.dxf")

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1