Outils pour utilisateurs

Outils du site


visionbut3

Cours 2023 provisoire: https://bvdp.inetdoc.net/files/iut/cours_vision_but3_2023.pdf

Planning du module

CM 4/11

  • initiation à la vision
  • spectre électromagnétique
  • comparaison caméras avec la vision humaine
  • capteurs d'images passifs

TD/TP 4/11

  • installation des outils
  • prise en main OpenCV
  • chargement et affichage image
  • caractérisation d'une image bitmap: résolution, rapport d'aspect, format, poids, compression
  • manipulation image: ROI
  • tracé de textes, lignes, rectangles, croix

TD/TP 6/11

  • espaces de couleurs RGBA, YUV, HSV, grey
  • génération de dégradé par synthèse
  • décimation chromatique
  • segmentation par seuillage dans l'espace HSV
  • effacement fond vert par opérateurs de masquage

Installations des outils pour travailler chez vous

Visual Studio Code

Installer Visual Studio Code: https://code.visualstudio.com/download

Nomacs

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.

Installation OpenCV

Taper dans une invite de commande:

pip install numpy  matplotlib  opencv-python --upgrade

Premier programme Python/OpenCV

Créer un dossier sur P:\etu-new\2024-2025\s5aii\s5aiiX\nom_prenom\tpvision et y télécharger le fichier suivant:

test1.py
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

Documentation OpenCV

TD1 Prise en main librairie OpenCV via Python

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

bvdp.inetdoc.net_files_iut_vision_img.jpg

Solution TD1

td1.py
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()

TD2 Espaces colorimétriques

Ressources: https://opencv24-python-tutorials.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#

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

td2.py
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()

Détection et comptage d'objets

Image avant traitement: bvdp.inetdoc.net_files_iut_tp_lpro_vision_riz.jpg

bvdp.inetdoc.net_files_iut_tp_lpro_vision_riz2.jpg

Code AII1

riz.py
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()

Exercice à faire

Images de cartes:

Images des symboles avec différentes rotations:

TD géométrie pour la vision

Solution pour le rendu de cube:

synthese.py
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()

TP reconstruction 3D monoculaire et par stéréovision

bvdp.inetdoc.net_files_iut_vision_imaobj1_rect.jpg

bvdp.inetdoc.net_files_iut_vision_imaobj2_rect.jpg

tpstereo.py
#/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()
visionbut3.txt · Dernière modification : 2024/11/21 19:59 de bvandepo