Commit 69f72bd8 authored by Quentin Chabanne's avatar Quentin Chabanne

Upload New File

parent 7cf55aa5
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from matplotlib import pyplot as plt #library to plot figures\n",
"import scipy.signal as signal\n",
"%matplotlib qt"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"En photographie, \n",
"* on considère que tous les objets situé à 1000 fois la focale de l’objectif utilisé sont à l’infini.\n",
"* un rayon venant de l'infini passe par le foyer\n",
"* un rayon passant par le centre optique n'est pas dévié\n",
"\n",
"![definition optiques](./optique%20geometrique.png)\n",
"\n",
"https://www.vision-doctor.com\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"taille de l'image en pixel : 1080 lignes x 1920 colonnes, soit 2.1 Mpixels\n",
"taille d'un pixel sur le capteur: 3.0278 x 3.0260 µm, soit une surface de 9.162182 µm²\n",
"angle du champ de vue 117.10° pour une focale de 1.00\n"
]
}
],
"source": [
"#paramètres appareil photo TLC2000 https://brinno.eu/en/bcc2000\n",
"#info du site f/2.0, full HD 1080p, champ de vue 118°, taille capteur 1/2.7\"\n",
"name=\"TLC2000\"\n",
"f=1 # focal en mm (lens :BCS019 , f=1mm ? je l'ai estimé à partir du champ de vue fourni 118°)\n",
"N = 2.0 # ouverture f /2.0 \n",
"longCapteur= np.array([3.27,5.81]) # en mm # 1 /2.7” CMOS Sensor 2.0 Mega Pixel. 16/9 ?\n",
"nbPixel=np.array([1080,1920]) #full HD1080 1080 lignes de 1920 pixels\n",
"totPixel=nbPixel[0]*nbPixel[1]/1000/1000 # nb de pixels en MegaPixel\n",
"taillePixel=longCapteur/nbPixel*1000 #taille d'un pixel en µm : en general, il y a RGB => est qu'il ne faut pas x 2 (1R, 1 B et 2 G) ?\n",
"surfPixel=taillePixel[0] * taillePixel[1] #surface d'un pixel en µm² \n",
"print(f\"taille de l'image en pixel : {nbPixel[0]} lignes x {nbPixel[1]} colonnes, soit {totPixel:.1f} Mpixels\")\n",
"print(f\"taille d'un pixel sur le capteur: {taillePixel[0]:.4f} x {taillePixel[1]:.4f} µm, soit une surface de {surfPixel:0.6f} µm²\")\n",
"\n",
"\n",
"champVue=2*np.arctan(longCapteur[0]/2/f)*180/np.pi #angle du champ de vue en °\n",
"print(f\"angle du champ de vue {champVue:.2f}° pour une focale de {f:.2f}\")\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"taille de l'image en pixel : 1080 lignes x 1920 colonnes, soit 2.1 Mpixels\n",
"taille d'un pixel sur le capteur: 3.0278 x 3.0260 µm, soit une surface de 9.162182 µm²\n",
"angle du champ de vue 10.38° pour une focale de 18.00\n"
]
}
],
"source": [
"#paramètres appareil photo TLC2000 https://brinno.eu/en/bcc2000\n",
"#info du site f/2.0, full HD 1080p, champ de vue 118°, taille capteur 1/2.7\"\n",
"name=\"TLC2000\"\n",
"f=18# focal en mm (lens :BCS019 , f=1mm ? je l'ai estimé à partir du champ de vue fourni 118°)\n",
"N = 1.2 # ouverture f /2.0 \n",
"longCapteur= np.array([3.27,5.81]) # en mm # 1 /2.7” CMOS Sensor 2.0 Mega Pixel. 16/9 ?\n",
"nbPixel=np.array([1080,1920]) #full HD1080 1080 lignes de 1920 pixels\n",
"totPixel=nbPixel[0]*nbPixel[1]/1000/1000 # nb de pixels en MegaPixel\n",
"taillePixel=longCapteur/nbPixel*1000 #taille d'un pixel en µm : en general, il y a RGB => est qu'il ne faut pas x 2 (1R, 1 B et 2 G) ?\n",
"surfPixel=taillePixel[0] * taillePixel[1] #surface d'un pixel en µm² \n",
"print(f\"taille de l'image en pixel : {nbPixel[0]} lignes x {nbPixel[1]} colonnes, soit {totPixel:.1f} Mpixels\")\n",
"print(f\"taille d'un pixel sur le capteur: {taillePixel[0]:.4f} x {taillePixel[1]:.4f} µm, soit une surface de {surfPixel:0.6f} µm²\")\n",
"\n",
"\n",
"champVue=2*np.arctan(longCapteur[0]/2/f)*180/np.pi #angle du champ de vue en °\n",
"print(f\"angle du champ de vue {champVue:.2f}° pour une focale de {f:.2f}\")\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"taille de l'image en pixel : 3000 lignes x 4000 colonnes, soit 12.0 Mpixels\n",
"taille d'un pixel sur le capteur: 1.9 x 1.9 µm, soit une surface de 3.5 µm²\n",
"angle du champ de vue 10.58° pour une focale de 30.50 mm\n"
]
}
],
"source": [
"#paramètres appareil photo PowerShotG15\n",
"name='PowerShotG5'\n",
"f=30.5 # focal en mm entre 6.1mm et 30.5mm\n",
"N = 1.8 # ouverture entre 1.8 et 2.8\n",
"longCapteur= np.array([5.65,7.53]) # en mm # 1 /1.7” CMOS Sensor 12.0 Mega Pixel. 4/3 ?\n",
"nbPixel=np.array([3000,4000]) #3000 lignes de 4000 pixels\n",
"totPixel=nbPixel[0]*nbPixel[1]/1000/1000 # nb de pixels en MegaPixel\n",
"taillePixel=longCapteur/nbPixel*1000 #taille d'un pixel en µm : en general, il y a RGB => est qu'il ne faut pas x 2 (1R, 1 B et 2 G) ?\n",
"surfPixel=taillePixel[0] * taillePixel[1] #surface d'un pixel en µm²\n",
"print(f\"taille de l'image en pixel : {nbPixel[0]} lignes x {nbPixel[1]} colonnes, soit {totPixel:.1f} Mpixels\")\n",
"print(f\"taille d'un pixel sur le capteur: {taillePixel[0]:.1f} x {taillePixel[1]:.1f} µm, soit une surface de {surfPixel:0.1f} µm²\")\n",
"\n",
"\n",
"champVue=2*np.arctan(longCapteur[0]/2/f)*180/np.pi #angle du champ de vue en °\n",
"print(f\"angle du champ de vue {champVue:.2f}° pour une focale de {f:.2f} mm\")\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## La profondeur de champ\n",
"\n",
"![profondeur de champ](pronfondeur%20de%20champ.png)\n",
"\n",
"On considère que si l'image d'un point objet est plus petite que $c$ (cercle de confusion), alors l'image est nette. \n",
"\n",
"$D$ est l'ouverture et $f$ est la focale de l'objectif.\n",
"\n",
"La mise au point se fait sur l'objet à la distance $\\|p\\|$.\n",
"\n",
"\n",
"\n",
"Par definition, $D=\\frac{f}{N}$. De plus, $\\frac{1}{f}= \\frac{1}{p_k'}-\\frac{1}{p_k}$.\n",
"\n",
"$\\frac{c}{D}=\\frac{p_2'}{p'-p_2'}$ => $\\|p_2\\|=\\frac{\\|p\\|{\\frac{f^2}{Nc}}}{-\\|p\\|+f+\\frac{f^2}{Nc}}$ \n",
"\n",
"avec l'hypothèse $\\frac{f^2}{Nc}-\\|p\\| >> f$, on a $\\|p_2\\|=\\frac{\\|p\\|{\\frac{f^2}{Nc}}}{-\\|p\\|+\\frac{f^2}{Nc}}$ \n",
"\n",
"d'où si $\\|p\\|=\\frac{f^2}{Nc}$ alors $\\|p_2\\|=\\infty$ cas hyperfocale\n",
"\n",
"avec l'hypothèse $\\frac{f^2}{Nc}+\\|p\\| >> f$, $\\|p_1\\|=\\frac{\\|p\\|{\\frac{f^2}{Nc}}}{\\|p\\|+\\frac{f^2}{Nc}}$\n",
"\n",
"d'où si $\\|p\\|=\\frac{f^2}{Nc}$ alors $\\|p_1\\|=\\frac{\\|p\\|}{2}$ cas hyperfocale\n",
"\n",
"source : https://fr.wikipedia.org/wiki/Profondeur_de_champ"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"PowerShotG5\n",
"la focale est de 30.50 mm et l'ouverture de 1/ 1.80\n",
"angle du champ de vue 10.58° pour une focale de 30.50 mm,\n",
"on considere un cercle de confusion de 1.0 pixel(s) capteur\n",
"Cas hyperfocale : si mise au point à 274.41 m, on est net entre 137.21m et l'infini\n"
]
}
],
"source": [
"c=1*taillePixel[0]/1000 # diametre du cercle de confusion en mm , j'ai mis la taille d'un pixel (à vérifier que c'est judicieux)\n",
"H=f**2/N/c/1000 #en m, distance hyperfocale\n",
"print(name)\n",
"print(f\"la focale est de {f:.2f} mm et l'ouverture de 1/ {N:.2f}\")\n",
"print(f\"angle du champ de vue {champVue:.2f}° pour une focale de {f:.2f} mm,\") \n",
"print(f\"on considere un cercle de confusion de {c*1000/taillePixel[0]:.1f} pixel(s) capteur\")\n",
"print(f\"Cas hyperfocale : si mise au point à {H:.2f} m, on est net entre {H/2:.2f}m et l'infini\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"PowerShotG5\n",
"à 300 m, on a dépassé l'hyperfocale\n",
"à 300 m, le champ de vue (10.58°) forme une zone de 55.6 m\n",
"un pixel représente alors 1.9 cm\n"
]
}
],
"source": [
"# parametres arbre\n",
"p=300 # distance (en m) à laquelle se trouve l'objet en m (mise au point)\n",
"\n",
"print(name)\n",
"#zone de netteté\n",
"p1=p*H/(p+H) # debut de zone de netteté\n",
"p2=p*H/(H-p) # fin de zone de netteté\n",
"if p<H:\n",
" print(f\"si mise au point à {p:.2f} m, on est net entre {p1:.2f} m et {p2:.2f} m\")\n",
"else:\n",
" print(f\"à {p} m, on a dépassé l'hyperfocale\")\n",
" p1=H/2\n",
" p2=float('inf') \n",
"\n",
"#resolution\n",
"dx=2*p*np.tan(np.pi*champVue/2/180) # en m, zone vue par le champ de vue\n",
"dcapteur=dx/np.min(nbPixel)*100 # en cm, taille réelle d'un pixel\n",
"print(f\"à {p} m, le champ de vue ({champVue:.2f}°) forme une zone de {dx:.1f} m\" ) #taille de la zone perpendiculaire\n",
"print(f\"un pixel représente alors {dcapteur:.1f} cm\")\n",
"\n",
"#autre methode mais qui donne le meme resultat\n",
"#dcapteur=1*np.max(taillePixel)/1000 # (en mm) on considere un pixel sur le capteur\n",
"#dx=dcapteur/f*p #taille original du détail sur le capteur en m\n",
"#print(f\"à {p} m, un pixel voit un détail de {dx*100:.1f} cm \") #les résultats me semblent exagérés...j'essaye de verifier avec le powershotG15\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## essai de modelisation\n",
"![model](./model.png)\n",
"\n",
"si l'angle de la caméra, $\\alpha$, devient petit, le modèle n'a plus trop de sens car cela revient en prendre des photos de face et non par dessus.\n",
"\n",
"Dans ce cas, utilisez uniquement les valeurs de p1 et p2 pour définir la zone nette.\n",
"\n",
"si la caméra photographie le haut de la canopée ($\\alpha$ important), zp1 et zp2 peuvent définir la zone nette"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"#juste pour faire des tests\n",
"#ca correspond plus ou moins au schema ci dessus\n",
"name=\"model\"\n",
"champVue=17\n",
"p=16.5\n",
"p1=13\n",
"p2=19\n",
"#h=7.3 \n",
"#alpha=25 "
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"à 424.2640687119285 m, on a dépassé l'hyperfocale\n",
"model\n",
"focale = 30.50 mm, h= 300 m, dist=424.3 m, p1=137.2 m, p2=inf m\n",
"la zone nette se trouve entre z1p=222.0 m et z2p=405.4 m\n",
"en zp1, un pixel représente 3.718348593414414 cm\n",
"en zp2, un pixel représente 5.025059721244474 cm\n"
]
},
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x14d44a838e0>]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"h=300 #en m, hauteur par rapport à la canopee à photographier\n",
"alpha=45 #en degre, angle de la camera\n",
"\n",
"p=h/np.sin(alpha*np.pi/180) #distance de visee\n",
"p1=p*H/(p+H) # debut de zone de netteté\n",
"p2=p*H/(H-p) # fin de zone de netteté\n",
"if p<H:\n",
" print(f\"si mise au point à {p:.2f} m, on est net entre {p1:.2f} m et {p2:.2f} m\")\n",
"else:\n",
" print(f\"à {p} m, on a dépassé l'hyperfocale\")\n",
" p1=H/2\n",
" p2=float('inf') \n",
"\n",
"print(name)\n",
"print(f\"focale = {f:.2f} mm, h= {h} m, dist={p:.1f} m, p1={p1:.1f} m, p2={p2:.1f} m\")\n",
"\n",
"z1=h/np.tan((alpha+champVue/2)*np.pi/180)\n",
"if (alpha-champVue/2)<=0: #le chanp passe au dessus de l'horizon\n",
" z2=float('inf')\n",
"else:\n",
" z2=h/np.tan((alpha-champVue/2)*np.pi/180)\n",
"zf=h/np.tan((alpha)*np.pi/180) \n",
"\n",
"\n",
"dz1=np.sqrt(h**2+z1**2) #en m\n",
"dz2=np.sqrt(h**2+z2**2) #en m\n",
"dzf=np.sqrt(h**2+zf**2) #en m, distance de mise au point\n",
"if False: # mettre true pour afficher\n",
" print(f\"z1={z1:.1f} m\")\n",
" print(f\"zf={zf:.1f} m\")\n",
" print(f\"z2={z2:.1f} m\")\n",
" print(f\"dz1={dz1:.1f} m\")\n",
" print(f\"dzf={dzf:.1f} m\")\n",
" print(f\"dz2={dz2:.1f} m\")\n",
" \n",
"if (dz2<p1/np.cos(champVue/2*np.pi/180)) or (dz1>p2/np.cos(champVue/2*np.pi/180)):\n",
" print(\"pas d'images nettes possible\")\n",
"else: \n",
" if dz1>p1*np.cos(champVue/2*np.pi/180):\n",
" z1p=z1 #point z1p hors champ de vue\n",
" else:\n",
" z1p=p1/np.cos(alpha*np.pi/180)-h*np.tan(alpha*np.pi/180)\n",
"\n",
" if dz2<p2*np.cos(champVue/2*np.pi/180):\n",
" z2p=z2 #point z2p hors champ de vue\n",
" else:\n",
" z2p=p2/np.cos(alpha*np.pi/180)-h*np.tan(alpha*np.pi/180)\n",
" print(f\"la zone nette se trouve entre z1p={z1p:.1f} m et z2p={z2p:.1f} m\")\n",
" \n",
" dx1=2*dz1*np.tan(np.pi*champVue/2/180) # en m, zone vue par le champ de vue à la distance dz1\n",
" dcapteur1=dx1/np.min(nbPixel)*100 # en cm, taille réelle d'un pixel\n",
" dx2=2*dz2*np.tan(np.pi*champVue/2/180) # en m, zone vue par le champ de vue à la distance dz2\n",
" dcapteur2=dx2/np.min(nbPixel)*100 # en cm, taille réelle d'un pixel\n",
" print(f\"en zp1, un pixel représente {dcapteur1} cm\")\n",
" print(f\"en zp2, un pixel représente {dcapteur2} cm\")\n",
"\n",
"plt.figure()\n",
"plt.plot(0,0,'o') #origine\n",
"plt.plot(0,h,'x') #camera\n",
"plt.plot([0,200],[0,0],'b')\n",
"plt.plot([0,zf],[h,0],'r:') #visee\n",
"plt.plot([0,z1],[h,0],'b:') # champ de vue\n",
"plt.plot([0,z2],[h,0],'b:') # chanp de vue\n",
"plt.plot([0,z1p],[h,0],'ro') # chanp de vue\n",
"plt.plot([0,z2p],[h,0],'ro') # chanp de vue\n",
"plt.plot(p1*np.cos(alpha*np.pi/180),h-p1*np.sin(alpha*np.pi/180),'ro')\n",
"plt.plot(p2*np.cos(alpha*np.pi/180),h-p2*np.sin(alpha*np.pi/180),'ro')"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.7"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "7173c644f055d2a259e0a2c1bc40b18a8a24299549bc16b9f24368822b3a4f54"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment