pour travailler en double écran en C02, utiliser la prise vga et configurer en 1920*1080 à gauche de mon écran et utiliser vscode pour zoomer sur le code
Cours 2023 provisoire: https://bvdp.inetdoc.net/files/iut/cours_vision_but3_2023.pdf
=====Planning du module=====
====TD et TP OML 7,10,13/11====
* modélisation et étalonnage de capteur : balance numérique
* ajustement d'une fonction linéaire à 2 ou plus points 2D
* ajustement d'une fonction quadratique à 3 ou plus points 2D
====CM 6/11====
* initiation à la vision
* spectre électromagnétique
* comparaison caméras avec la vision humaine
====TD/TP 8/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 9/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
====CM 13/11====
* cours capteurs pour la robotique
====CM/TD 15/11====
* cours traitement d'image
* filtrage gaussien
* opérateurs morphologiques
====TD/TP 16/11====
* démonstration caméras industrielle ueye
* réglage focale, zoom, ouverture
* réglage durée d'exposition, gain, lut, horloge, ROI...
* démonstration caméra RGBD Realsense
====TD/TP 20/11====
* début détection/localisation/comptage riz
* conversion RGB->gris
* analyse d'histogrammes
* seuillage manuel et adaptatif par méthode d'Otsu
* seuillage adaptatif local
* début opérateurs morphologiques (érosion...)
====TD/TP 21/11====
* fin opérateurs morphologiques (érosion...)
* extraction des contours
* calcul des caractéristiques géométriques des contours (périmètre, aire...)
====TD/TP 22/11====
* fin détection/localisation/comptage riz
* détermination d'un algorithme de classification simple à base de seuils
* méthode de classification KNN
* reconnaissance par corrélation/différence avec gestion de masque et génération des images en rotation
====CM 27/11====
* cours géométrie pour la vision
====TD/TP 27/11====
* application du modèle direct de la camera pour la synthèse
* calcul des paramètres intrinsèques et extrinsèques
* génération de l'image d'un cube en rendu filaire
====TD/TP 29/11====
* estimation des paramètres du modèle de caméra par étalonnage avec mire plane
====TD/TP 30/11====
* reconstruction de modèle 3D par vision monoculaire et stéréoscopique
SUPERS TUTOS: https://www.geeksforgeeks.org/opencv-python-tutorial/
=====Installations des outils=====
Chez vous installer Visual Studio Code: https://code.visualstudio.com/download
Logiciel pour visualiser les images, alternative à geeqie: https://nomacs.org/
version portable à installer sur D:\ : 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 pour Windows IUT=====
taper dans une invite de commande:
pip install numpy matplotlib opencv-python --upgrade
ne pas installer la version headless qui ne permet pas la visualisation des images
pip install opencv-contrib-python-headless
pip uninstall opencv-contrib-python-headless
Créer un dossier sur P:\etu-new\s5aii\s5aiiX\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:
code
ouvrir le dossier que vous venez de créer
Run
indique qu'il n'y a pas extension python
cliquer sur install coté de Python IntelliSense(Pylance) Microsoft
python3
Python 3.9.7
import cv2 as cv
cv.__version__
'4.8.1'
probleme: il faut caster en int les l20 de homographie.py et a completer sur wiki:
image=cv.line(image, (int(srcPoints[n][0]),int(srcPoints[n][1])),(int(srcPoints[(n+1)%4][0]),int(srcPoints[(n+1)%4][1])), color, thickness)
====Documentation OpenCV====
https://pypi.org/project/opencv-python/
lien vers documentation openCV: https://docs.opencv.org/4.8.0/
====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
{{https://bvdp.inetdoc.net/files/iut/vision/img.jpg}}
=====Solution TD1=====
import numpy as np
import cv2
import math
print("version openCV:"+str( cv2.__version__ ))
#Load an color image in grayscale
img = cv2.imread('img.jpg',0)
print("img:" +str(img) )
# Create a black image
#img = np.zeros((512,512,3), np.uint8)
# Draw a diagonal blue line with thickness of 5 px
cv2.line(img,(0,0),(511,511),255,5,cv2.LINE_AA)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'BUT3',(10,500), font, 4,255,2,cv2.LINE_AA)
cv2.imwrite('imggray.png',img)
#load image in color
img = cv2.imread('img.jpg',1)
px = img[100,100]
print("px:"+str(px))
img[200,100] = [255,0,0]
px = img[200,100]
print("px:"+str(px))
for i in range(0,255):
for j in range(0,255):
img[200+j,100+i]=[i,j,0]
print("img.shape:"+str(img.shape))
print("img.dtype:"+str(img.dtype))
xo=692
yo=252
larg=60
haut=60
x1=434
y1=218
ROI = img[yo:yo+haut, xo:xo+larg]
for i in range(0,3):
img[y1+i*100:y1+haut+i*100, x1:x1+larg] = ROI
cv2.imwrite('imgcolor.png',img)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
import numpy as np
import cv2
import math
print("version openCV:"+str( cv2.__version__ ))
# Load an color image in grayscale
img = cv2.imread('img.jpg',0)
print(img)
# Create a black image
#img = np.zeros((512,512,3), np.uint8)
#pour une image couleur
#cv2.line(img,(0,0),(511,511),(255,0,0),5)
cv2.line(img,(0,0),(511,511),128,5)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'BUT3',(10,500), font, 4,255,2,cv2.LINE_AA)
cv2.imwrite('imggray.png',img)
#---------------------------------
# Load an color image in color
img = cv2.imread('img.jpg',1)
print(img)
cv2.imwrite('imgcolor.png',img)
px = img[100,100]
print("px:" + str(px))
blue = img[100,100,0]
print("blue:" +str(blue))
print("image shape: " +str(img.shape)+" , image type:" +str(img.dtype))
yo=257
xo=695
larg=60
haut=60
ROI=img[yo:yo+haut, xo:xo+larg]
x1=435
y1=220
img[y1:y1+haut, x1:x1+larg] = ROI
for i in range(0,3):
x1=435+i*120
y1=220
img[y1:y1+haut, x1:x1+larg] = ROI
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
=====Solution TD2=====
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("conversions supportées:"+ str(flags))
#exit(0)
#Load an color image in grayscale
img = cv2.imread('img.jpg',0)
print("img:" +str(img) )
# Create a black image
#img = np.zeros((512,512,3), np.uint8)
# Draw a diagonal blue line with thickness of 5 px
cv2.line(img,(0,0),(511,511),255,5,cv2.LINE_AA)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'BUT3',(10,500), font, 4,255,2,cv2.LINE_AA)
cv2.imwrite('imggray.png',img)
#load image in color
img = cv2.imread('img.jpg',1)
px = img[100,100]
print("px:"+str(px))
img[200,100] = [255,0,0]
px = img[200,100]
print("px:"+str(px))
for i in range(0,255):
for j in range(0,255):
img[200+j,100+i]=[i,j,0]
print("img.shape:"+str(img.shape))
print("img.dtype:"+str(img.dtype))
xo=692
yo=252
larg=60
haut=60
x1=434
y1=218
ROI = img[yo:yo+haut, xo:xo+larg]
for i in range(0,3):
img[y1+i*100:y1+haut+i*100, x1:x1+larg] = ROI
# Convert BGR to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_blue, upper_blue)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(img,img, mask= mask)
xgazon=350
ygazon=618
print("gazon:"+str(hsv[ygazon,xgazon]))
#gazon:[ 36 171 183]
lower_gazon = np.array([26,50,50])
upper_gazon= np.array([46,255,255])
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_gazon, upper_gazon)
# Bitwise-AND mask and original image
mask= cv2.bitwise_not( mask)
res = cv2.bitwise_and(img,img, mask= mask)
cv2.imwrite('imgres.png',res)
cv2.imshow('image res',res)
cv2.imwrite('imgcolor.png',img)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
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:"+str(flags))
# Load an color image in grayscale
img = cv2.imread('img.jpg',0)
print(img)
# Create a black image
#img = np.zeros((512,512,3), np.uint8)
#pour une image couleur
#cv2.line(img,(0,0),(511,511),(255,0,0),5)
cv2.line(img,(0,0),(511,511),128,5)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'BUT3',(10,500), font, 4,255,2,cv2.LINE_AA)
cv2.imwrite('imggray.png',img)
#---------------------------------
# Load an color image in color
img = cv2.imread('img.jpg',1)
print(img)
cv2.imwrite('imgcolor.png',img)
px = img[100,100]
print("px:" + str(px))
blue = img[100,100,0]
print("blue:" +str(blue))
print("image shape: " +str(img.shape)+" , image type:" +str(img.dtype))
yo=257
xo=695
larg=60
haut=60
ROI=img[yo:yo+haut, xo:xo+larg]
x1=435
y1=220
img[y1:y1+haut, x1:x1+larg] = ROI
for i in range(0,3):
x1=435+i*120
y1=220
img[y1:y1+haut, x1:x1+larg] = ROI
for r in range(0,256):
for g in range(0,256):
img[100+g,100+r]=(100,g,r)
# Convert BGR to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
xgazon=346
ygazon=641
print("gazon:"+ str(hsv[ygazon,xgazon]))
lower_gazon = np.array([38-10,50,50])
upper_gazon = np.array([38+10,255,255])
# Threshold the HSV image to get only blue colors
#mask = cv2.inRange(hsv, lower_blue, upper_blue)
mask = cv2.inRange(hsv, lower_gazon, upper_gazon)
mask=cv2.bitwise_not(mask)
# Bitwise-AND mask and original image
imgres = cv2.bitwise_and(img,img, mask= mask)
cv2.imwrite('imgres.png',imgres)
#cv2.imshow('image',img)
cv2.imshow('image',imgres)
cv2.waitKey(0)
cv2.destroyAllWindows()
=====Détection et comptage d'objets=====
Image avant traitement:
{{https://bvdp.inetdoc.net/files/iut/tp_lpro_vision/riz.jpg}}
=====Solution intermédiaire aii 2=====
import numpy as np
import cv2
from matplotlib import pyplot as plt
im = cv2.imread('riz.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
#imgray=imgray*0.5
#imgray=imgray.astype(np.uint8)
# affichage histogramme:
#https://opencv24-python-tutorials.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.html
hist,bins = np.histogram(imgray.flatten(),256,[0,256])
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max()/ cdf.max()
plt.plot(cdf_normalized, color = 'b')
plt.hist(imgray.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()
#autre methode pour l'histogramme:
#cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
hist = cv2.calcHist([imgray],[0],None,[256],[0,256])
#hist = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
#plt.imshow(hist,interpolation = 'nearest')
#plt.show()
#print(str(hist))
#seuillage brut ou manuel
ret,thresh1 = cv2.threshold(imgray,150,255,cv2.THRESH_BINARY)
#seuillage Otsu's thresholding
ret2,th2 = cv2.threshold(imgray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print("ret2: "+str(ret2))
cv2.imwrite('riz_out.png',im)
cv2.imwrite('riz_gray.png',imgray)
cv2.imwrite('riz_otsu.png',th2)
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(th2,kernel,iterations = 1)
cv2.imwrite('riz_otsu_erosion.png',erosion)
dilation = cv2.dilate(erosion,kernel,iterations = 1)
cv2.imwrite('riz_otsu_erosion_dilatation.png',dilation)
cv2.imshow('image',th2)
cv2.waitKey(0)
cv2.destroyAllWindows()
=====Solution intermédiaire aii 1=====
import numpy as np
import cv2
from matplotlib import pyplot as plt
im = cv2.imread('riz.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist([imgray],[0],None,[256],[0,256])
#hist = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
#plt.imshow(hist,interpolation = 'nearest')
#plt.show()
#print(str(hist))
#imgray=imgray*0.5
#imgray=imgray.astype(np.uint8)
if False:
#https://opencv24-python-tutorials.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.html
hist,bins = np.histogram(imgray.flatten(),256,[0,256])
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max()/ cdf.max()
plt.plot(cdf_normalized, color = 'b')
plt.hist(imgray.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()
print(im.shape)
cv2.imwrite('riz_gray.png',imgray)
# Otsu's thresholding
ret,thresh1 = cv2.threshold(imgray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print ("ret: "+str(ret))
#seuillage à la main
#ret,thresh1 = cv2.threshold(imgray,150,255,cv2.THRESH_BINARY)
cv2.imwrite('riz_thresh1.png',thresh1)
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(thresh1,kernel,iterations = 2)
cv2.imwrite('riz_thresh1_erosion.png',erosion)
dilatation = cv2.dilate(erosion,kernel,iterations = 1)
cv2.imwrite('riz_thresh1_erosion_dilatation.png',dilatation)
cv2.imshow('image',thresh1)
cv2.waitKey(0)
cv2.destroyAllWindows()
=====TD géométrie pour la vision=====
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()
=====TP reconstruction 3D monoculaire et par stéréovision=====
{{https://bvdp.inetdoc.net/files/iut/vision/imaobj1_rect.jpg}}
{{https://bvdp.inetdoc.net/files/iut/vision/imaobj2_rect.jpg}}
#/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()
====Solution====
#/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
#---------------------------
dimRepere=0.10
axis = np.float32([[0,0,0], [dimRepere,0,0], [0,dimRepere,0], [0,0,dimRepere]]).reshape(-1,3)
img1 = cv2.line(img1, projeterPoint(axis[0],iC1w),projeterPoint(axis[1],iC1w), (0,0,255), 1)
img1 = cv2.line(img1, projeterPoint(axis[0],iC1w),projeterPoint(axis[2],iC1w), (0,255,0), 1)
img1 = cv2.line(img1, projeterPoint(axis[0],iC1w),projeterPoint(axis[3],iC1w), (255,0,0), 1)
img2 = cv2.line(img2, projeterPoint(axis[0],iC2w),projeterPoint(axis[1],iC2w), (0,0,255), 1)
img2 = cv2.line(img2, projeterPoint(axis[0],iC2w),projeterPoint(axis[2],iC2w), (0,255,0), 1)
img2 = cv2.line(img2, projeterPoint(axis[0],iC2w),projeterPoint(axis[3],iC2w), (255,0,0), 1)
#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
#---------------------------
monoculaire=True
if monoculaire: #monoculaire
if i%2==0: #point 3D dans le plan de la mire z=0
A = np.zeros((3,3), np.float32)
B = np.zeros((3,1), np.float32)
n=0
A[n][0]=iC1w[2][0]*mu-iC1w[0][0]
A[n][1]=iC1w[2][1]*mu-iC1w[0][1]
A[n][2]=iC1w[2][2]*mu-iC1w[0][2]
B[n]= -iC1w[2][3]*mu+iC1w[0][3]
n=1
A[n][0]=iC1w[2][0]*mv-iC1w[1][0]
A[n][1]=iC1w[2][1]*mv-iC1w[1][1]
A[n][2]=iC1w[2][2]*mv-iC1w[1][2]
B[n]= -iC1w[2][3]*mv+iC1w[1][3]
n=2
A[n][0]=0
A[n][1]=0
A[n][2]=1
B[n]= 0
X=np.linalg.inv(A)@B
Xz0=X.copy()
else: #point 3D à la verticale du point précédent
#A = np.zeros((4,3), np.float32)
#B = np.zeros((4,1), np.float32)
A = np.zeros((3,3), np.float32)
B = np.zeros((3,1), np.float32)
n=0
A[n][0]=iC1w[2][0]*mu-iC1w[0][0]
A[n][1]=iC1w[2][1]*mu-iC1w[0][1]
A[n][2]=iC1w[2][2]*mu-iC1w[0][2]
B[n]= -iC1w[2][3]*mu+iC1w[0][3]
n=1
A[n][0]=iC1w[2][0]*mv-iC1w[1][0]
A[n][1]=iC1w[2][1]*mv-iC1w[1][1]
A[n][2]=iC1w[2][2]*mv-iC1w[1][2]
B[n]= -iC1w[2][3]*mv+iC1w[1][3]
#Solution utilisant une altitude connue pour les points de la face supérieure
#n=2
#A[n][0]=0
#A[n][1]=0
#A[n][2]=1
#B[n]= 0.1 #10cm
#Solution utilisant le point d'indice précédent dans le plan z=0 pour déterminer une des coordonnées (x ici) du point courant
n=2
A[n][0]=1
A[n][1]=0
A[n][2]=0
B[n]= Xz0[0]
#ou bien
#A[n][0]=0
#A[n][1]=1
#A[n][2]=0
#B[n]= Xz0[1]
print("A:" +str(A))
print("B:" +str(B))
#X= (np.linalg.inv(A.transpose() @ A) @ A.transpose() ) @ B
X=np.linalg.inv(A)@B
else: #stereo
A = np.zeros((4,3), np.float32)
B = np.zeros((4,1), np.float32)
n=0
A[n][0]=iC1w[2][0]*mu-iC1w[0][0]
A[n][1]=iC1w[2][1]*mu-iC1w[0][1]
A[n][2]=iC1w[2][2]*mu-iC1w[0][2]
B[n]= -iC1w[2][3]*mu+iC1w[0][3]
n=1
A[n][0]=iC1w[2][0]*mv-iC1w[1][0]
A[n][1]=iC1w[2][1]*mv-iC1w[1][1]
A[n][2]=iC1w[2][2]*mv-iC1w[1][2]
B[n]= -iC1w[2][3]*mv+iC1w[1][3]
n=2
A[n][0]=iC2w[2][0]*mu2-iC2w[0][0]
A[n][1]=iC2w[2][1]*mu2-iC2w[0][1]
A[n][2]=iC2w[2][2]*mu2-iC2w[0][2]
B[n]= -iC2w[2][3]*mu2+iC2w[0][3]
n=3
A[n][0]=iC2w[2][0]*mv2-iC2w[1][0]
A[n][1]=iC2w[2][1]*mv2-iC2w[1][1]
A[n][2]=iC2w[2][2]*mv2-iC2w[1][2]
B[n]= -iC2w[2][3]*mv2+iC2w[1][3]
X= (np.linalg.inv(A.transpose() @ A) @ A.transpose() ) @ B
print("X( "+str(i)+" ): "+str(X))
listeM[i][:]=X.transpose()
#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()