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/
version portable: https://github.com/nomacs/nomacs/releases/latest/download/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__ )) couleur=True if not couleur: # Load an color image in grayscale img = cv2.imread('img.jpg',cv2.IMREAD_GRAYSCALE) if img is None: print("probleme chargement image") exit(-1) print(img) print("img.shape:" +str(img.shape)) # Draw a diagonal blue line with thickness of 5 px cv2.line(img,(0,0),(img.shape[1]-1,img.shape[0]-1),255,5) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img,'BUT3',(10,500), font, 4,255,2,cv2.LINE_AA ) cv2.imwrite('imggray.png',img) cv2.imshow('image',img) cv2.waitKey(0) cv2.destroyAllWindows() else: # Load an color image in grayscale img = cv2.imread('img.jpg',cv2.IMREAD_COLOR) if img is None: print("probleme chargement image") exit(-1) print(img) print("img.shape:" +str(img.shape)) # Draw a diagonal blue line with thickness of 5 px cv2.line(img,(0,0),(img.shape[1]-1,img.shape[0]-1),(0,0,255),5) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img,'BUT3',(10,500), font, 4,(0,255,0),2,cv2.LINE_AA ) px = img[200,100] # v,u print("px:"+str(px)) img[200,100] = [255,0,255] for up in range(0,255): for vp in range(0,255): img[200+vp,100+up] = [up,0,vp] u0=692 v0=252 larg=60 haut=60 u1=434 v1=218 ROI=img[v0:v0+haut,u0:u0+larg] cv2.imwrite('roi.png',ROI) #copie directe #img[v1:v1+haut,u1:u1+larg]=ROI #copie pixel par pixel en faisant une symétrie par rapport à l'axe vertical (inefficace en python) for u in range(0,larg-1): for v in range(0,haut-1): img[v1+v,u1+u]=ROI[v,larg-u-1] for v1 in range(100,400,100): u1=int(v1*1.5)+220 img[v1:v1+haut,u1:u1+larg]=ROI 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
import numpy as np import cv2 import math print("version openCV:"+str( cv2.__version__ )) flags = [i for i in dir(cv2) if i.startswith('COLOR_')] print(flags) couleur=True if not couleur: # Load an color image in grayscale img = cv2.imread('img.jpg',cv2.IMREAD_GRAYSCALE) if img is None: print("probleme chargement image") exit(-1) print(img) print("img.shape:" +str(img.shape)) # Draw a diagonal blue line with thickness of 5 px cv2.line(img,(0,0),(img.shape[1]-1,img.shape[0]-1),255,5) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img,'BUT3',(10,500), font, 4,255,2,cv2.LINE_AA ) cv2.imwrite('imggray.png',img) cv2.imshow('image',img) cv2.waitKey(0) cv2.destroyAllWindows() else: # Load an color image in grayscale img = cv2.imread('img.jpg',cv2.IMREAD_COLOR) if img is None: print("probleme chargement image") exit(-1) print(img) print("img.shape:" +str(img.shape)) # Draw a diagonal blue line with thickness of 5 px cv2.line(img,(0,0),(img.shape[1]-1,img.shape[0]-1),(0,0,255),5) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img,'BUT3',(10,500), font, 4,(0,255,0),2,cv2.LINE_AA ) px = img[200,100] # v,u print("px:"+str(px)) img[200,100] = [255,0,255] for up in range(0,255): for vp in range(0,255): img[200+vp,100+up] = [up,0,vp] u0=692 v0=252 larg=60 haut=60 u1=434 v1=218 ROI=img[v0:v0+haut,u0:u0+larg] cv2.imwrite('roi.png',ROI) #copie directe #img[v1:v1+haut,u1:u1+larg]=ROI #copie pixel par pixel en faisant une symétrie par rapport à l'axe vertical (inefficace en python) for u in range(0,larg-1): for v in range(0,haut-1): img[v1+v,u1+u]=ROI[v,larg-u-1] for v1 in range(100,400,100): u1=int(v1*1.5)+220 img[v1:v1+haut,u1:u1+larg]=ROI cv2.imwrite('imgcolor.png',img) # Convert BGR to HSV hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # define range of green color in HSV lower_green = np.array([26,50,50]) upper_green = np.array([46,255,225]) # Threshold the HSV image to get only green colors mask = cv2.inRange(hsv, lower_green, upper_green) mask=cv2.bitwise_not(mask) # Bitwise-AND mask and original image res = cv2.bitwise_and(img,img, mask= mask) cv2.imshow('image',res) cv2.waitKey(0) cv2.destroyAllWindows()
import numpy as np import cv2 import math from matplotlib import pyplot as plt print("version openCV:"+str( cv2.__version__ )) #niveau de gris if True: # Load an color image in grayscale img = cv2.imread('riz2.jpg',0) print("img.dtype : "+ str(img.dtype)) print("img.shape : "+ str(img.shape)) #le premier scalaire est la hauteur de l'image if img is None: print("Fichier image foireux") exit() print(img) ''' kernel = np.ones((5,5),np.float32)/25 img = cv2.filter2D(img,-1,kernel) img = cv2.filter2D(img,-1,kernel) img = cv2.filter2D(img,-1,kernel) ''' #kernel = np.ones((1,1),np.float32)/4 #img = cv2.filter2D(img,-1,kernel) #plt.hist(img.ravel(),256,[0,256]); plt.show() ret,thresh1 = cv2.threshold(img,200,255,cv2.THRESH_BINARY) # Otsu's thresholding ret2,thresh2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) print("ret2:"+str(ret2)) kernel = np.ones((3,3),np.uint8) erosion = cv2.erode(thresh2,kernel,iterations = 2) dilatation = cv2.dilate(erosion,kernel,iterations = 1) #imgxor = cv2.bitwise_xor(thresh2,erosion) imgxor = cv2.bitwise_xor(thresh2,dilatation) imcolor = cv2.cvtColor(dilatation,cv2.COLOR_GRAY2BGR) imcolor[4,2]=(255,0,0) contours, hierarchy = cv2.findContours(dilatation,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) compteur=0 for data in contours: print("The contours have this data "+str(data)) area = cv2.contourArea(data) hull = cv2.convexHull(data) hull_area = cv2.contourArea(hull) solidity = float(area)/hull_area (x,y),(MA,ma),angle = cv2.fitEllipse(data) if MA<ma: tmp=MA MA=ma ma=tmp aspect=MA/ma x=int(x) y=int(y) #if compteur%2==0: if area>=20 and area<=200 and solidity>0.8 and aspect>2: #cv2.drawContours(imcolor,data,-1,(0,255,0),1) cv2.line(imcolor,(x,y-2),(x,y+2),(0,255,0),1) cv2.line(imcolor,(x-2,y),(x+2,y),(0,255,0),1) else: cv2.drawContours(imcolor,data,-1,(0,0,255),1) compteur=compteur+1 cv2.imwrite('imggray.png',img) cv2.imwrite('imgthresh.png',thresh2) cv2.imwrite('imgerosion.png',erosion) cv2.imwrite('imgdilatation.png',dilatation) cv2.imwrite('imgcolor.png',imcolor) cv2.imwrite('imgxor.png',imgxor) cv2.imshow('image',imcolor) cv2.waitKey(0) cv2.destroyAllWindows()
Solution pour le rendu de cube:
import cv2 import numpy as np import math print("==============================================================") taillecube=1 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("==============================================================") cRw=np.float32([[1,0,0],[0,-1,0],[0,0,-1]]) cTw=np.float32([[0],[0],[3]]) cRTw = np.hstack((cRw,cTw)) cRTw = np.vstack((cRTw,[0,0,0,1])) print("cRTw:"+str(cRTw)) print("==============================================================") eu=0.00001 #10um ev=eu #champ de vision en degré fovhdegres=100 demifovh=(fovhdegres/2)*math.pi/180 alphau=400/math.tan(demifovh) print("alphau:"+str(alphau)) f=alphau*eu print("f:"+str(f)+" m") alphav=alphau demifovv=math.atan(300/alphav) fovvdegres=demifovv*2*180/math.pi print("fovvdegres:"+str(fovvdegres)) #======================================= pu=400 pv=300 iCc=np.float32([[alphau,0,pu,0],[0,alphav,pv,0],[0,0,1,0]]) print("iCc:"+str(iCc)) iCw=iCc@cRTw print("iCw:"+str(iCw)) #------------------ def projeterPoint(M): 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) #------------------ M= np.float32([0,0,0]) m= projeterPoint(M) # Create a black image img = np.zeros((pv*2,pu*2), np.uint8) for seg in listeseg: print("seg:"+str(seg)) m1=projeterPoint(listeM[seg[0]]) m2=projeterPoint(listeM[seg[1]]) print("m1:"+str(m1)) print("m2:"+str(m2)) cv2.line(img,m1,m2,255,1,cv2.LINE_AA) cv2.imshow('image',img) cv2.waitKey(0) cv2.destroyAllWindows()
#/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 image, 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()