Cours 2023 provisoire: https://bvdp.inetdoc.net/files/iut/cours_vision_but3_2023.pdf
Installer Visual Studio Code: https://code.visualstudio.com/download
Logiciel pour visualiser les images, alternative à geeqie: https://nomacs.org/ https://github.com/nomacs/nomacs/releases/latest/download/nomacs-portable-win.zip
version portable téléchargeable: https://bvdp.inetdoc.net/files/iut/nomacs-portable-win.zip
régler la langue en anglais
Cliquer sur Panels→Toolbars→Statusbar pour afficher les informations sur l'image en bas à droite.
Pour relever des coordonnées de pixels dans les images, lire en bas a gauche.
Taper dans une invite de commande:
pip install numpy matplotlib opencv-python --upgrade
Créer un dossier sur P:\etu-new\2024-2025\s5aii\s5aiiX\nom_prenom\tpvision et y télécharger le fichier suivant:
import numpy as np import cv2 import math print("version openCV:"+str( cv2.__version__ ))
Lancer Visual Studio Code:
Bureau->Applications locales geii->Visual Studio Code
Ouvrir le dossier que vous venez de créer:
File->Open Folder, choisir, puis cliquer sur sélectionner le dossier Run->Start Debugging si VSCode indique qu'il n'y a pas d'extension python; cliquer sur install coté de Python IntelliSense(Pylance) Microsoft
https://pypi.org/project/opencv-python/
lien vers documentation openCV: https://docs.opencv.org/4.8.0/
Nous allons commencer par prendre en main la librairie OpenCV via le langage Python: https://opencv24-python-tutorials.readthedocs.io/en/latest/py_tutorials/py_tutorials.html
Image à télécharger dans votre dossier de projet
import numpy as np
import cv2
import math
print("version openCV:"+str( cv2.__version__ ))
img = cv2.imread('img.jpg',cv2.IMREAD_COLOR)
print(img)
print(type(img))
print(img.shape)
print(img.dtype)
print("rapport d aspect: "+str(img.shape[1]/img.shape[0]))
print("pixel en 1,1:"+str(img[1][1]))
img[1][1][1]=255
img[1][1][0]=0
img[1][1][2]=0
print("pixel en 1,1:"+str(img[1][1]))
#cv2.imwrite('imggray.png',img)
#cv2.imwrite('imggray.jpg',img)
ball = img[280:340, 330:390]
img[273:333, 100:160] = ball
haut=60
larg=60
v0=264
u0=700
ball = img[v0:v0+haut, u0:u0+larg]
for n in range(3):
v1=224
u1=442
img[v1:v1+haut, n*100+u1:n*100+u1+larg] = ball
for n in range(256):
for m in range(256):
img[n][m][0]= m
img[n][m][1]= 0
img[n][m][2]= n
cv2.imwrite('imgcolor.png',img)
#
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Espace colorimétrique YUV: https://fr.wikipedia.org/wiki/YUV
Décimation chromatique en YUV: https://www.latelierducable.com/tv-televiseur/yuv-420-ycbcr-422-rgb-444-cest-quoi-le-chroma-subsampling/ et https://wiki.videolan.org/YUV/
Espace colorimétrique HSV (TSV en français): https://fr.wikipedia.org/wiki/Teinte_Saturation_Valeur
https://fr.wikipedia.org/wiki/Cercle_chromatique#/media/Fichier:CYM_color_wheel.png
https://mathworld.wolfram.com/MoirePattern.html
https://www.lesnumeriques.com/photo/qu-est-ce-que-le-moire-pu121721.html
https://www.techno-science.net/glossaire-definition/Moire-effet-de-contraste.html
https://fr.wikipedia.org/wiki/Transform%C3%A9e_en_cosinus_discr%C3%A8te
http://compressionimage.free.fr/dct/
https://fr.wikipedia.org/wiki/Sous-%C3%A9chantillonnage_de_la_chrominance
import numpy as np
import cv2
import math
print("version openCV:"+str( cv2.__version__ ))
img = cv2.imread('img.jpg')
print(img)
print(type(img))
print(img.shape)
print(img[637][633][:])
img[637][633][0]= 255
img[637][633][1]= 0
img[637][633][2]= 0
haut=60
larg=60
v0=264
u0=700
ball = img[v0:v0+haut, u0:u0+larg]
for n in range(3):
v1=224
u1=442
img[v1:v1+haut, n*100+u1:n*100+u1+larg] = ball
cv2.line(img,(0,0),(511,511),(255,0,0),1,cv2.LINE_AA)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV
lower_green = np.array([35,0,0])
upper_green = np.array([85,255,255])
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_green, upper_green)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(img,img, mask= mask)
for m in range(256):
for n in range(256):
img[n][m][0]= m
img[n][m][1]= 0
img[n][m][2]= n
for m in range(img.shape[1]):
for n in range(img.shape[0]):
g=(m%2)*255
img[n][m][0]= g
img[n][m][1]= g
img[n][m][2]= g
#cv2.line(img,(0,0),(511,511),(255,0,0),1,cv2.LINE_4)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv2.LINE_AA)
flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
print(flags)
'''
Enumerator
FILLED
Python: cv.FILLED
LINE_4
Python: cv.LINE_4
4-connected line
LINE_8
Python: cv.LINE_8
8-connected line
LINE_AA
Python: cv.LINE_AA
antialiased line
'''
#cv2.imshow('image',img)
cv2.imshow('image',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
#cv2.imwrite('imggray.png',img)
#cv2.imwrite('imggray.jpg',img)#cv2.imwrite('imggray.jpg',img)
cv2.imwrite('imgcolor.png',img)
import numpy as np
import cv2
import math
print("version openCV:"+str( cv2.__version__ ))
img = cv2.imread('riz2.jpg',0)
# Appliquer le facteur 1/2 aux valeurs des pixels pour tester le seuil adaptatif
#img = (img / 2).astype(np.uint8)
#ou
#img = cv2.convertScaleAbs(img, alpha=0.5, beta=0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print("ret2:"+str(ret2))
print(img)
print(type(img))
print(img.shape)
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(th2,kernel,iterations = 2)
#affichage difference
#cv2.imshow('image',th2-erosion)
dilation = cv2.dilate(erosion,kernel,iterations = 1)
cv2.imwrite('dilation.png',dilation)
#affichage difference
#cv2.imshow('image',th2-dilation)
imgcolor = cv2.cvtColor(dilation, cv2.COLOR_GRAY2BGR)
cpt=0
contours, hierarchy = cv2.findContours(dilation,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for contour in contours:
print("The contours have this data " +str(contour))
M = cv2.moments(contour)
print(str(M))
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
imgcolor[cy][cx]=[255,0,0]
area = cv2.contourArea(contour)
perimeter = cv2.arcLength(contour,True)
hull = cv2.convexHull(contour)
rect = cv2.minAreaRect(contour)
aspectratio=max(rect[1])/min(rect[1])
hullarea = cv2.contourArea(hull)
#box = cv2.boxPoints(rect)
#box = np.int0(box)
solidity=float(area)/hullarea
#if cpt%2==0:
if area>20 and area<200 and aspectratio> 2 and aspectratio<6 and solidity>0.8:
cv2.drawContours(imgcolor,contour,-1,(0,255,0),1)
else:
cv2.drawContours(imgcolor,contour,-1,(0,0,255),1)
cpt=cpt+1
cv2.imshow('image',imgcolor)
cv2.waitKey(0)
cv2.destroyAllWindows()
Lien vers doc pour paramétrisation de Rodrigues: https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html?highlight=pnp#void%20Rodrigues(InputArray%20src,%20OutputArray%20dst,%20OutputArray%20jacobian)
Lien vers doc pour modèle de caméra et étalonnage: https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
Fichier de départ:
#!/usr/bin/python3 import cv2 import numpy as np import math print("==============================================================") #modèle 3D filaire d'un cube: taillecube=1 #unité métrique pour le coté du cube listeM = np.float32([[0,0,0], [taillecube,0,0],[taillecube,taillecube,0], [0,taillecube,0], [0,0,taillecube], [taillecube,0,taillecube],[taillecube,taillecube,taillecube], [0,taillecube,taillecube]]) print("listeM:"+str(listeM)) listeseg=[[0,1],[1,2],[2,3],[3,0],[4,5],[5,6],[6,7],[7,4],[0,4],[1,5],[2,6],[3,7]] print("listeseg:"+str(listeseg)) print("==============================================================")
Solution TD:
#!/usr/bin/python3 import cv2 import numpy as np import math print("==============================================================") #modèle 3D filaire d'un cube: taillecube=1 #unité métrique pour le coté du cube listeM = np.float32([[0,0,0], [taillecube,0,0],[taillecube,taillecube,0], [0,taillecube,0], [0,0,taillecube], [taillecube,0,taillecube],[taillecube,taillecube,taillecube], [0,taillecube,taillecube]]) print("listeM:"+str(listeM)) listeseg=[[0,1],[1,2],[2,3],[3,0],[4,5],[5,6],[6,7],[7,4],[0,4],[1,5],[2,6],[3,7]] print("listeseg:"+str(listeseg)) print("==============================================================") #https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html?highlight=pnp#void%20Rodrigues(InputArray%20src,%20OutputArray%20dst,%20OutputArray%20jacobian) rvecs=(math.pi/4.)*np.float32([0,0,1]) print(str(rvecs)) rot, jacobian=cv2.Rodrigues(rvecs) print(str(rot)) print(str(jacobian)) tvecs=np.float32([[3,-1,5]]).transpose() print(str(tvecs)) cRTw=np.concatenate( (rot,tvecs) ,axis=1) print(str(cRTw)) cRTw=np.concatenate( (cRTw,np.float32([[0,0,0,1]])) ,axis=0) print(str(cRTw)) #========================================================= eu=0.00001 ev=eu largeur=800 hauteur=600 fovhdegres=120 demifovhradian=(fovhdegres/2.)*(math.pi/180.) pu=largeur/2 pv=hauteur/2 alphau=pu/math.tan(demifovhradian) print(str(alphau)) f=alphau*eu print(str(f)) alphav=f/ev iCc=np.float32([[alphau,0,pu,0],[ 0, alphav,pv,0], [0,0,1,0]]) print(str(iCc)) iCw=iCc@cRTw print(str(iCw)) ############################# def projeterPoint(M): print("M:"+str(M)) M=np.append(M,1) print("M:"+str(M)) m=iCw@M print("m:"+str(m)) #m=m*(1/m[2]) mu=m[0]/m[2] mv=m[1]/m[2] #arrondi et cast mu=int(round(mu,0)) mv=int(round(mv,0)) print("mu:"+str(mu)) print("mv:"+str(mv)) return (mu,mv) ############################# im=np.zeros((hauteur,largeur),np.uint8) for i in range(len(listeM)): (mu,mv)=projeterPoint(listeM[i]) im[mv,mu]=255 for i in range(len(listeseg)): (mu1,mv1)=projeterPoint(listeM[listeseg[i][0]]) (mu2,mv2)=projeterPoint(listeM[listeseg[i][1]]) cv2.line(im,(mu1,mv1),(mu2,mv2),255,1,cv2.LINE_AA) cv2.imwrite('imgcube2025.png',im) cv2.imshow('image',im) cv2.waitKey(0) cv2.destroyAllWindows()
Animation:
Animation synthese for i in range(100): taillecube=1+i*0.01 listeM = np.float32([[0,0,0], [taillecube,0,0],[taillecube,taillecube,0], [0,taillecube,0], [0,0,taillecube], [taillecube,0,taillecube],[taillecube,taillecube,taillecube], [0,taillecube,taillecube]]) print("listeM:"+str(listeM)) listeseg=[[0,1],[1,2],[2,3],[3,0],[4,5],[5,6],[6,7],[7,4],[0,4],[1,5],[2,6],[3,7]] print("listeseg:"+str(listeseg)) #------------------ #rodrigues rvecs = np.float32([0,0,0]) ''' rvecs = np.float32([0,2*np.pi*i/100.,0]) rvecs = np.float32([2*np.pi*i/100.,0,0]) rvecs = np.float32([0,0,2*np.pi*i/100.]) ''' rvecs = np.float32([2*np.pi*i/100.,2*np.pi*i/100.,2*np.pi*i/100.]) ------ code pour synthétiser une image ------ cv2.imshow('animation', img) if cv2.waitKey(1) == ord('q'): # press q to terminate the loop cv2.destroyAllWindows() break
Exemple de la balance: tpomlbut3
#/usr/bin/python3 import numpy as np import cv2 import glob filename1="imaobj1_rect.jpg" filename2="imaobj2_rect.jpg" img1 = cv2.imread(filename1) if(len(img1.shape)<3): img1 = cv2.cvtColor(img1,cv2.COLOR_GRAY2BGR) img2 = cv2.imread(filename2) if(len(img2.shape)<3): img2 = cv2.cvtColor(img2,cv2.COLOR_GRAY2BGR) h, w = img1.shape[:2] print("h:"+str(h)) print("w:"+str(w)) #------------------ def projeterPoint(M,iCw): #print("M:"+str(M)) M = np.append(M, 1) #print("M:"+str(M)) m=iCw@M #deshomogénéisation mu=m[0]/m[2] mv=m[1]/m[2] #arrondi pour avoir des positions entières mu=int(round(mu,0)) mv=int(round(mv,0)) #print("mu:"+str(mu)) #print("mv:"+str(mv)) return (mu,mv) #------------------ alphau=2149.349810656287900 alphav=2146.276553276586100 pu=412.626457723086160 pv=355.723365602020240 rvec1 = np.float32([ -3.125480e-001 , -2.316874e+000 , 1.048207e-001 ]) tvec1 = 0.001 * np.float32([ [4.813190e+001] , [-1.258122e+002] , [1.066916e+003] ]) rvec2 = np.float32([ 6.592006e-001 , -2.262313e+000 , -3.064294e-001]) tvec2 = 0.001 * np.float32([ [2.557518e+001] , [-6.888417e+001] , [1.091155e+003] ]) matR1,jac1=cv2.Rodrigues(rvec1) print("matR1:"+str(matR1)) matR2,jac2=cv2.Rodrigues(rvec2) print("matR2:"+str(matR2)) #affichage comme TD synthese cRT1w=np.hstack((matR1,tvec1)) cRT1w = np.vstack((cRT1w,[0,0,0,1])) cRT2w=np.hstack((matR2,tvec2)) cRT2w = np.vstack((cRT2w,[0,0,0,1])) print("cRTw: "+str(cRT1w)) #print("mtx: "+str(mtx)) iCc=np.float32([[alphau,0,pu,0],[0,alphav,pv,0],[0,0,1,0]]) print("iCc:"+str(iCc)) iC1w=iCc@cRT1w print("iC1w:"+str(iC1w)) iC2w=iCc@cRT2w print("iC2w:"+str(iC2w)) #--------------------------- #TODO: afficher un repère de 10cm de coté sur chaque image sur chaque image #--------------------------- #liste des points pour les 2 images, mu puis mv listem1 = np.int_([[490,96], [329,83] , [510,119] , [359,107], [493,156],[339,151],[525,189],[373,180],[507,230], [353,223],[534,253],[385,250],[514,302],[361,304], [544,333],[393,336],[523,377],[369,383], [400,252], # ce point n'est pas observé dans l'image [254,264]]) listem2 = np.int_([[448,194], [290,184] , [450,233] , [297,228], [420,249],[265,243],[427,297],[272,294],[391,311], [241,308],[399,349],[250,354],[366,364],[212,367], [371,408],[216,417],[338,416],[179,420], [316,263], # ce point n'est pas observé dans l'image [162,228]]) if listem2.shape[0]!=listem1.shape[0]: print("les 2 listes de points doivent avoir le même nombre de points") exit(-1) listeM=np.zeros((listem2.shape[0],3), np.float32) #valeur par defaut pour le point 3D reconstruit X = np.zeros((3,1), np.float32) Xz0 = np.zeros((3,1), np.float32) for i,(mu,mv) in enumerate(listem1): img1 = cv2.circle(img1,(mu,mv), 3,(255,0,255), -1) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img1,str(i),(mu+10,mv), font, 1,(255,0,255),2,cv2.LINE_AA) #récupère le point correspondant dans l'image 2 mu2=listem2[i][0] mv2=listem2[i][1] img2 = cv2.circle(img2,(mu2,mv2), 3,(255,0,255), -1) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img2,str(i),(mu2+10,mv2), font, 1,(255,0,255),2,cv2.LINE_AA) #--------------------------- #TODO: Remplir listeM[i][:] avec les coordonnées 3D du point i #--------------------------- #image composée à partir des 2 images 1 et 2 imagecomposee = np.hstack((img1,img2)) filenameout="imaobj_rect-out.jpg" cv2.imwrite(filenameout,imagecomposee) cv2.imshow('dst',imagecomposee) cv2.waitKey(-1) cv2.destroyAllWindows() #----------------------------------------------- #matplot 3D #https://www.geeksforgeeks.org/three-dimensional-plotting-in-python-using-matplotlib/ #mettre à True pour activer le rendu 3D après fermeture de la fenêtre opencv if False: # importing mplot3d toolkits from mpl_toolkits import mplot3d import numpy as np import matplotlib.pyplot as plt fig = plt.figure() # syntax for 3-D projection ax = plt.axes(projection ='3d') # defining axes x = listeM[:,0] y = listeM[:,1] z = listeM[:,2] ax.scatter(x, y, z) ax.axis('equal') # syntax for plotting ax.set_title('3d Scatter plot geeks for geeks') plt.show()
Démo /home/bvandepo/Bureau/pythonb/ueye2023/uEye_SimpleLive_PyuEye_OpenCV/SimpleLive_Pyueye_OpenCV.py
brancher une carte arduino en USB et utiliser mire acrylique
Extension Python se met à jour à une version trop récente pour visual studio code
Si vous avez une fenêtre Interactive 1 qui affiche:
[Select a kernel](command:_notebook.selectKernel) to run cells. - Bandeau à gauche, icône du bas (extensions) - Taper python dans la zone de recherche - choisir Python juste en dessous - à droite de Uninstall, cliquer sur Install Specific Version - choisir 2025.6.1