Initial commit
BIN
29_grey.jpg
Normal file
After Width: | Height: | Size: 294 B |
BIN
30_small.jpg
Normal file
After Width: | Height: | Size: 523 B |
BIN
Algorithm.pdf
Normal file
BIN
IMG_0114b.JPG
Normal file
After Width: | Height: | Size: 323 KiB |
BIN
IMG_0114s.JPG
Normal file
After Width: | Height: | Size: 216 KiB |
BIN
IMG_0114s.bmp
Normal file
After Width: | Height: | Size: 1.8 MiB |
BIN
IMG_0115b.JPG
Normal file
After Width: | Height: | Size: 335 KiB |
BIN
IMG_0115s.JPG
Normal file
After Width: | Height: | Size: 228 KiB |
3
Notes valeurs de D, f et deltaX
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
D = 36mm
|
||||||
|
f = 38mm
|
||||||
|
deltaX = 8cm
|
30
RGB2grey.c
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
unsigned char** RGB2grey(unsigned char*** image, int width, int height)
|
||||||
|
{
|
||||||
|
unsigned char** grey;
|
||||||
|
int x,y;
|
||||||
|
|
||||||
|
if((grey = malloc(sizeof(*grey) * height)) == NULL)
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for(y = 0; y <= height; y++)
|
||||||
|
{
|
||||||
|
if((grey[y] = malloc(sizeof(**grey) * width)) == NULL)
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(y = 0; y <= height; y++)
|
||||||
|
{
|
||||||
|
for(x = 0; x <= width; x++)
|
||||||
|
{
|
||||||
|
grey[y][x] = (unsigned char) (0.2125*image[y][x][0] + 0.7154*image[y][x][1] + 0.0721*image[y][x][2]);
|
||||||
|
//Formula found here : https://fr.wikipedia.org/wiki/Niveau_de_gris
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grey;
|
||||||
|
}
|
BIN
Rapport/IMG_0114s.JPG
Normal file
After Width: | Height: | Size: 216 KiB |
BIN
Rapport/IMG_0115s.JPG
Normal file
After Width: | Height: | Size: 228 KiB |
BIN
Rapport/Left.JPG
Normal file
After Width: | Height: | Size: 2.4 MiB |
BIN
Rapport/Right.JPG
Normal file
After Width: | Height: | Size: 2.2 MiB |
27
Rapport/biblio.bib
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
@misc{article,
|
||||||
|
title = {Distance Estimation Algorithm for Stereo Pair Images},
|
||||||
|
author = {TjandranegaraB, Edwin},
|
||||||
|
howpublished="\url{http://docs.lib.purdue.edu/ecetr/64/}",
|
||||||
|
year = {article daté de 2005, dernière consultation en décembre 2012},
|
||||||
|
}
|
||||||
|
|
||||||
|
@misc{article2,
|
||||||
|
title = {Distance measuring based on stereoscopic pictures},
|
||||||
|
author = {Mrovlje1, Jernej and Vranči, Damir},
|
||||||
|
howpublished="\url{http://photon07.pd.infn.it:5210/users/dazzi/Thesis_doctorate/Info/Chapter_6/Stereoscopy_(Mrovlje).pdf}",
|
||||||
|
year = {article daté de 2008, dernière consultation en décembre 2012},
|
||||||
|
}
|
||||||
|
|
||||||
|
@misc{templateMatching,
|
||||||
|
title = {OpenCV wiki page about template matching},
|
||||||
|
author = {},
|
||||||
|
howpublished="\url{http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html}",
|
||||||
|
year = {dernière consultation en janvier 2013},
|
||||||
|
}
|
||||||
|
|
||||||
|
@misc{phaseCorrelation,
|
||||||
|
title = {Wikipedia page about phase correlation},
|
||||||
|
author = {},
|
||||||
|
howpublished="\url{http://en.wikipedia.org/wiki/Phase_correlation}",
|
||||||
|
year = {dernière consultation en janvier 2013},
|
||||||
|
}
|
42
Rapport/rapport.aux
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
\relax
|
||||||
|
\providecommand\hyper@newdestlabel[2]{}
|
||||||
|
\catcode`:\active
|
||||||
|
\catcode`;\active
|
||||||
|
\catcode`!\active
|
||||||
|
\catcode`?\active
|
||||||
|
\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
|
||||||
|
\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined
|
||||||
|
\global\let\oldcontentsline\contentsline
|
||||||
|
\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}}
|
||||||
|
\global\let\oldnewlabel\newlabel
|
||||||
|
\gdef\newlabel#1#2{\newlabelxx{#1}#2}
|
||||||
|
\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}
|
||||||
|
\AtEndDocument{\ifx\hyper@anchor\@undefined
|
||||||
|
\let\contentsline\oldcontentsline
|
||||||
|
\let\newlabel\oldnewlabel
|
||||||
|
\fi}
|
||||||
|
\fi}
|
||||||
|
\global\let\hyper@last\relax
|
||||||
|
\gdef\HyperFirstAtBeginDocument#1{#1}
|
||||||
|
\providecommand\HyField@AuxAddToFields[1]{}
|
||||||
|
\providecommand\HyField@AuxAddToCoFields[2]{}
|
||||||
|
\select@language{french}
|
||||||
|
\@writefile{toc}{\select@language{french}}
|
||||||
|
\@writefile{lof}{\select@language{french}}
|
||||||
|
\@writefile{lot}{\select@language{french}}
|
||||||
|
\@writefile{toc}{\contentsline {section}{\numberline {1}Objectif}{1}{section.1}}
|
||||||
|
\@writefile{toc}{\contentsline {section}{\numberline {2}M\IeC {\'e}thode choisie}{1}{section.2}}
|
||||||
|
\@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Distance euclidienne dans l'espace RGB}{1}{subsection.2.1}}
|
||||||
|
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Cross-correlation \emph {via} FFT}{1}{subsection.2.2}}
|
||||||
|
\citation{article}
|
||||||
|
\citation{article2}
|
||||||
|
\citation{templateMatching}
|
||||||
|
\citation{phaseCorrelation}
|
||||||
|
\bibstyle{plain-fr}
|
||||||
|
\bibdata{biblio}
|
||||||
|
\bibcite{templateMatching}{1}
|
||||||
|
\@writefile{toc}{\contentsline {section}{\numberline {3}R\IeC {\'e}sultats}{2}{section.3}}
|
||||||
|
\@writefile{toc}{\contentsline {section}{\numberline {4}Optimisations possibles}{2}{section.4}}
|
||||||
|
\bibcite{phaseCorrelation}{2}
|
||||||
|
\bibcite{article2}{3}
|
||||||
|
\bibcite{article}{4}
|
30
Rapport/rapport.bbl
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
\begin{thebibliography}{1}
|
||||||
|
\expandafter\ifx\csname fonteauteurs\endcsname\relax
|
||||||
|
\def\fonteauteurs{\scshape}\fi
|
||||||
|
|
||||||
|
\bibitem{templateMatching}
|
||||||
|
Opencv wiki page about template matching.
|
||||||
|
\newblock
|
||||||
|
\url{http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html},
|
||||||
|
dernière consultation en janvier 2013.
|
||||||
|
|
||||||
|
\bibitem{phaseCorrelation}
|
||||||
|
Wikipedia page about phase correlation.
|
||||||
|
\newblock \url{http://en.wikipedia.org/wiki/Phase_correlation}, dernière
|
||||||
|
consultation en janvier 2013.
|
||||||
|
|
||||||
|
\bibitem{article2}
|
||||||
|
Jernej \bgroup\fonteauteurs\bgroup Mrovlje1\egroup\egroup{} et Damir
|
||||||
|
\bgroup\fonteauteurs\bgroup Vranči\egroup\egroup{} :
|
||||||
|
\newblock Distance measuring based on stereoscopic pictures.
|
||||||
|
\newblock
|
||||||
|
\url{http://photon07.pd.infn.it:5210/users/dazzi/Thesis_doctorate/Info/Chapter_6/Stereoscopy_(Mrovlje).pdf},
|
||||||
|
article daté de 2008, dernière consultation en décembre 2012.
|
||||||
|
|
||||||
|
\bibitem{article}
|
||||||
|
Edwin \bgroup\fonteauteurs\bgroup TjandranegaraB\egroup\egroup{} :
|
||||||
|
\newblock Distance estimation algorithm for stereo pair images.
|
||||||
|
\newblock \url{http://docs.lib.purdue.edu/ecetr/64/}, article daté de 2005,
|
||||||
|
dernière consultation en décembre 2012.
|
||||||
|
|
||||||
|
\end{thebibliography}
|
49
Rapport/rapport.blg
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
This is BibTeX, Version 0.99d (TeX Live 2012/Arch Linux)
|
||||||
|
Capacity: max_strings=35307, hash_size=35307, hash_prime=30011
|
||||||
|
The top-level auxiliary file: rapport.aux
|
||||||
|
The style file: plain-fr.bst
|
||||||
|
Database file #1: biblio.bib
|
||||||
|
Warning--to sort, need author or key in templateMatching
|
||||||
|
Warning--to sort, need author or key in phaseCorrelation
|
||||||
|
You've used 4 entries,
|
||||||
|
2238 wiz_defined-function locations,
|
||||||
|
554 strings with 5349 characters,
|
||||||
|
and the built_in function-call counts, 936 in all, are:
|
||||||
|
= -- 99
|
||||||
|
> -- 21
|
||||||
|
< -- 0
|
||||||
|
+ -- 10
|
||||||
|
- -- 6
|
||||||
|
* -- 34
|
||||||
|
:= -- 174
|
||||||
|
add.period$ -- 8
|
||||||
|
call.type$ -- 4
|
||||||
|
change.case$ -- 15
|
||||||
|
chr.to.int$ -- 0
|
||||||
|
cite$ -- 6
|
||||||
|
duplicate$ -- 28
|
||||||
|
empty$ -- 93
|
||||||
|
format.name$ -- 6
|
||||||
|
if$ -- 213
|
||||||
|
int.to.chr$ -- 0
|
||||||
|
int.to.str$ -- 4
|
||||||
|
missing$ -- 0
|
||||||
|
newline$ -- 23
|
||||||
|
num.names$ -- 4
|
||||||
|
pop$ -- 33
|
||||||
|
preamble$ -- 1
|
||||||
|
purify$ -- 11
|
||||||
|
quote$ -- 0
|
||||||
|
skip$ -- 28
|
||||||
|
stack$ -- 0
|
||||||
|
substring$ -- 44
|
||||||
|
swap$ -- 4
|
||||||
|
text.length$ -- 0
|
||||||
|
text.prefix$ -- 0
|
||||||
|
top$ -- 0
|
||||||
|
type$ -- 16
|
||||||
|
warning$ -- 2
|
||||||
|
while$ -- 4
|
||||||
|
width$ -- 5
|
||||||
|
write$ -- 40
|
||||||
|
(There were 2 warnings)
|
6
Rapport/rapport.out
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
\BOOKMARK [1][-]{section.1}{Objectif}{}% 1
|
||||||
|
\BOOKMARK [1][-]{section.2}{M\351thode choisie}{}% 2
|
||||||
|
\BOOKMARK [2][-]{subsection.2.1}{Distance euclidienne dans l'espace RGB}{section.2}% 3
|
||||||
|
\BOOKMARK [2][-]{subsection.2.2}{Cross-correlation via FFT}{section.2}% 4
|
||||||
|
\BOOKMARK [1][-]{section.3}{R\351sultats}{}% 5
|
||||||
|
\BOOKMARK [1][-]{section.4}{Optimisations possibles}{}% 6
|
BIN
Rapport/rapport.pdf
Normal file
101
Rapport/rapport.tex
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
\documentclass[10pt,a4paper]{article}
|
||||||
|
\usepackage{ifpdf}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage[francais]{babel}
|
||||||
|
\usepackage{lmodern}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{amsmath}
|
||||||
|
\usepackage{amsfonts}
|
||||||
|
\usepackage{amssymb}
|
||||||
|
\usepackage{enumitem}
|
||||||
|
\usepackage[margin=1.5cm]{geometry}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\usepackage{url}
|
||||||
|
|
||||||
|
\title{Projet de Physique Numérique : Mesure de distances par stéréoscopie}
|
||||||
|
\author{Lucas Verney}
|
||||||
|
\date{2012/2013}
|
||||||
|
\ifpdf
|
||||||
|
\pdfinfo {
|
||||||
|
/Author (Lucas Verney)
|
||||||
|
/Title (Projet de Physique Numérique : Mesure de distances par stéréoscopie)
|
||||||
|
}
|
||||||
|
\fi
|
||||||
|
\begin{document}
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
\section{Objectif}
|
||||||
|
Le but de ce projet était de déterminer des distances séparant un observateur d'un objet à partir de deux photos de cet objet prises en déplaçant horizontalement l'appareil entre les prises de vue. En utilisant la stéréoscopie, on peut en effet déterminer la distance nous séparant de l'objet, tout comme notre cerveau est capable d'estimer les distances nous séparant des objets à partir des ``images'' captées par nos yeux.
|
||||||
|
|
||||||
|
\bigskip
|
||||||
|
|
||||||
|
\underline{\emph{Exemple :}}
|
||||||
|
\medskip
|
||||||
|
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{cc}
|
||||||
|
\includegraphics[scale=0.25]{IMG_0114s.JPG} & \includegraphics[scale=0.25]{IMG_0115s.JPG} \\
|
||||||
|
\emph{Image de gauche} & \emph{Image de droite} \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\section{Méthode choisie}
|
||||||
|
Il faut, dans un premier temps, déterminer le déplacement en pixels de l'objet entre les deux images. Dans un deuxième temps, il faut traduire ce déplacement en distance réelle nous séparant de l'objet.
|
||||||
|
|
||||||
|
\subsection{Distance euclidienne dans l'espace RGB}
|
||||||
|
Pour déterminer le déplacement en pixels, on considère une grille de $n\times n$ pixels, qu'on superpose à notre image de gauche (par défaut, $n = 50$ dans le programme). Pour chaque carrés de $n\times n$ pixels, on cherche le carré qui lui correspond le plus dans l'image de droite. Pour ce faire, on va parcourir chaque pixel de l'image de droite et comparer le carré de l'image de gauche et le carré dont le coin supérieur gauche est le pixel courant dans l'image de droite.
|
||||||
|
|
||||||
|
Les images étant chargées en couleur (RGB), on est dans un espace à trois dimensions (R, G et B) dont les coordonnées des pixels sont entre $0$ et $255$ (profondeur de couleur de 8 bits). On peut donc estimer la ``distance'' séparant les deux carrés par la moyenne sur le carré des distances pixel à pixel où la distance pixel à pixel est la distance euclidienne standard ($=\sqrt{(R_2 - R_1)^2 + (G_2 - G_1)^2 + (B_2 - B_1)^2}$).
|
||||||
|
|
||||||
|
\subsection{Cross-correlation \emph{via} FFT}
|
||||||
|
Une autre possibilité est d'utiliser la cross-correlation (ou la phase correlation) afin de déterminer la position de notre objet.
|
||||||
|
|
||||||
|
On commence par charger les images en niveaux de gris et on récupère le carré qu'on considère dans une nouvelle image, de la même taille que l'image de droite. On complète cette image par du noir (des 0) qui n'interviendront donc pas dans la transformation de Fourier.
|
||||||
|
|
||||||
|
On effectue ensuite les transformations de fourier de chaque image et on multiplie le spectre de l'image de droite par le conjugué du spectre du carré dont on cherche la position. On normalise ensuite la transformation de Fourier (en divisant chaque la valeur de chaque point par son module) et on repasse en espace réel (\emph{via} une transformation de Fourier inverse.
|
||||||
|
|
||||||
|
On cherche ensuite la valeur de la plus grande amplitude sur cette image, qui correspond à la position du carré qu'on cherche.
|
||||||
|
|
||||||
|
\bigskip
|
||||||
|
|
||||||
|
Une fois cette distance déterminée, on peut en déduire la distance nous séparant de l'objet en utilisant les formules explicitées dans \cite{article}. Connaissant les caractéristiques de l'appareil, il est facile de traduire le déplacement en pixels précédent en distance réelle.
|
||||||
|
|
||||||
|
\section{Résultats}
|
||||||
|
Le programme obtenu a été testée sur le jeu d'images suivant (les tests ont été effectués en considérant le coin inférieur gauche du carré noir) :
|
||||||
|
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{cc}
|
||||||
|
\includegraphics[scale=0.05]{Left.JPG} & \includegraphics[scale=0.05]{Right.JPG} \\
|
||||||
|
\emph{Image de gauche} & \emph{Image de droite} \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
Le programme décrit précédemment permet de déterminer très précisément le déplacement du coin inférieur gauche et on ne peut obtenir une meilleure précision manuellement. Ce résultat a été obtenu en une vingtaine de secondes en utilisant les $4$ c{\oe}urs du processeur, ce qui est relativement long. En effet, pour parcourir toute l'image avec la méthode précédente et des carrés de $50$ pixels de large, il faudrait environ $30h$.
|
||||||
|
|
||||||
|
Après conversion du déplacement en pixels en distance réelle, on trouve une distance réelle de $15cm$ contre $35cm$ en réalité (en utilisant des caractéristiques ``moyennes'' pour l'appareil photo). Cependant, le déplacement étant convenablement détecté, cet écart provient d'une méconnaissance des caractéristiques précises de l'appareil photo utilisé (notamment sa distance focale).
|
||||||
|
|
||||||
|
En conclusion, cette technique nous permet de déterminer des distances très précisément mais est très coûteuse en ressources et il est difficilement envisageable de couvrir une photo entière avec cette méthode.
|
||||||
|
|
||||||
|
La technique utilisant la transformée de fourier rapide est nettement plus rapide (une vingtaine de secondes par image) et donne des résultats légèrement moins précis mais largement comparables.
|
||||||
|
|
||||||
|
\medskip
|
||||||
|
\emph{Remarque :} Il faut également noter qu'on ne détermine pas la distance nous séparant d'un objet (ou d'un point) précis mais une moyenne de cette distance sur un carré de $n$ pixels de large. Il faut donc choisir la taille de ce carré petite devant l'échelle caractéristique de variation des distances (liée à la taille transversale des objets).
|
||||||
|
|
||||||
|
\emph{Remarque :} On peut également utiliser un algorithme de détection de contours (type filtre de Sobel qui calcule le ``gradient'' de l'image) pour travailler sur une image en niveau de gris et déterminer les distances nous séparant des contours des objets, ceci afin d'obtenir une meilleure précision sur des images chargées.
|
||||||
|
|
||||||
|
\section{Optimisations possibles}
|
||||||
|
Comme on l'a vu précédemment, la méthode employée est très coûteuse en ressources. On peut envisager diverses optimisations :
|
||||||
|
\begin{itemize}
|
||||||
|
\item On peut envisager d'appliquer un filtre de détection de contours (type filtre de Sobel) avant de travailler sur l'image. On peut alors se restreindre aux zones d'intérêt, c'est-à-dire aux contours représentés par des pixels blancs.
|
||||||
|
\item Pour accélérer le calcul des distances, on peut envisager de paralléliser au maximum les opérations. Dans le code présenté, on utilise jusqu'à $4$ c{\oe}urs du processeur mais l'utilisation de la puce graphique pourrait accélérer le calcul, celle-ci travaillant naturellement avec des calculs parallèles.
|
||||||
|
\item Jusqu'ici, on n'a envisagé qu'un déplacement horizontal (ou vertical en travaillant sur une image retournée). On pourrait envisager le cas d'un déplacement quelconque dans l'espace (translation) en adaptant les formules.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\nocite{article2}
|
||||||
|
\nocite{templateMatching}
|
||||||
|
\nocite{phaseCorrelation}
|
||||||
|
|
||||||
|
\bibliographystyle{plain-fr}
|
||||||
|
\bibliography{biblio}
|
||||||
|
\end{document}
|
BIN
Right2.JPG
Normal file
After Width: | Height: | Size: 311 KiB |
BIN
Stereoscopy_(Mrovlje).pdf
Normal file
165
bmp.c
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//Note : BMP files are written from left to right but from bottom to top !
|
||||||
|
|
||||||
|
struct file_header
|
||||||
|
{
|
||||||
|
char signature[3];
|
||||||
|
int size;
|
||||||
|
int reserved;
|
||||||
|
int offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct img_header
|
||||||
|
{
|
||||||
|
int headerSize;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int planes;
|
||||||
|
int depth;
|
||||||
|
int compress;
|
||||||
|
int imgSize;
|
||||||
|
int resX;
|
||||||
|
int resY;
|
||||||
|
int colors;
|
||||||
|
int importantColors;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct file_header get_file_header(FILE* file)
|
||||||
|
{
|
||||||
|
struct file_header fh={"", 0, 0, 0};
|
||||||
|
|
||||||
|
fread(&fh.signature, 2, 1, file);
|
||||||
|
fread(&fh.size, 4, 1, file);
|
||||||
|
fread(&fh.reserved, 4, 1, file);
|
||||||
|
fread(&fh.offset, 4, 1, file);
|
||||||
|
|
||||||
|
return fh;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct img_header get_img_header(FILE* file)
|
||||||
|
{
|
||||||
|
struct img_header ih={0,0,0,0,0,0,0,0,0,0,0};
|
||||||
|
|
||||||
|
fread(&ih.headerSize, 4, 1, file);
|
||||||
|
fread(&ih.width, 4, 1, file);
|
||||||
|
fread(&ih.height, 4, 1, file);
|
||||||
|
fread(&ih.planes, 2, 1, file);
|
||||||
|
fread(&ih.depth, 2, 1, file);
|
||||||
|
fread(&ih.compress, 4, 1, file);
|
||||||
|
fread(&ih.imgSize, 4, 1, file);
|
||||||
|
fread(&ih.resX, 4, 1, file);
|
||||||
|
fread(&ih.resY, 4, 1, file);
|
||||||
|
fread(&ih.colors, 4, 1, file);
|
||||||
|
fread(&ih.importantColors, 4, 1, file);
|
||||||
|
|
||||||
|
return ih;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if(argc < 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error : you must specify a bmp image to open.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//All the variables we'll use
|
||||||
|
FILE *file;
|
||||||
|
const char* filename;
|
||||||
|
filename = argv[1];
|
||||||
|
struct file_header fileHeader;
|
||||||
|
struct img_header imageHeader;
|
||||||
|
int x, y, yImage;
|
||||||
|
unsigned char ***image;
|
||||||
|
|
||||||
|
file = fopen(filename, "rb"); //First, open the file in binary mode
|
||||||
|
|
||||||
|
if(file == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error : can't open the bmp image.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileHeader = get_file_header(file); //Get the file header and check it is a bmp file
|
||||||
|
|
||||||
|
if(strcmp(fileHeader.signature, "BM") != 0 && strcmp(fileHeader.signature, "BA") != 0 && strcmp(fileHeader.signature, "CI") != 0 && strcmp(fileHeader.signature, "CP") != 0 && strcmp(fileHeader.signature, "IC") != 0 && strcmp(fileHeader.signature, "PT") != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error : This file is not a valid BMP image.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
imageHeader = get_img_header(file); //Get the image header
|
||||||
|
|
||||||
|
if(imageHeader.compress != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error : The BMP file is compressed. This program can't open such files.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(imageHeader.depth != 24) //If it is not a "true-color" RGB bmp file (ie 24 bits per pixel)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error : This BMP is not a standard true-color BMP file. It may be a 256 colors BMP file for example.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Allocation dynamique pour l'image
|
||||||
|
if((image = malloc(sizeof(*image) * imageHeader.height)) == NULL)
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
for(y = 0; y <= imageHeader.height; y++)
|
||||||
|
{
|
||||||
|
if((image[y] = malloc(sizeof(**image) * imageHeader.width)) == NULL)
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(y = 0; y <= imageHeader.height; y++)
|
||||||
|
{
|
||||||
|
for(x = 0; x <= imageHeader.width; x++)
|
||||||
|
{
|
||||||
|
if((image[y][x] = malloc(sizeof(***image) * 3)) == NULL) //image[y][x][R,G,B]
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
image[y][x][0] = 0;
|
||||||
|
image[y][x][1] = 0;
|
||||||
|
image[y][x][2] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(file, fileHeader.offset, SEEK_SET); //We don't get all the possible headers, so go to the start of the image informations
|
||||||
|
|
||||||
|
for(y = 0; y <= imageHeader.height; y++) //Get all the values for all the pixels in the image
|
||||||
|
{
|
||||||
|
for(x = 0; x <= imageHeader.width; x++)
|
||||||
|
{
|
||||||
|
yImage = imageHeader.height - y; //Due to the fact that BMP file are written from bottom to top
|
||||||
|
fread(&image[yImage][x][2], 1, 1, file);
|
||||||
|
fread(&image[yImage][x][1], 1, 1, file);
|
||||||
|
fread(&image[yImage][x][0], 1, 1, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
printf("Output is : (Coordinates of the pixel) : value of each channel");
|
||||||
|
for(y = 0; y <= imageHeader.height; y++)
|
||||||
|
{
|
||||||
|
for(x = 0; x <= imageHeader.width; x++)
|
||||||
|
{
|
||||||
|
printf("(%d,%d) : R = %d,G = %d,B = %d\n", x, y, image[y][x][0], image[y][x][1], image[y][x][2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(image);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
10
makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
all: stereo bmp
|
||||||
|
|
||||||
|
stereo : stereo.o
|
||||||
|
gcc stereo.o -o stereo `pkg-config opencv --libs` -lm -lpthread -lfftw3 -lfftw3_threads
|
||||||
|
|
||||||
|
stereo.o : stereo.c
|
||||||
|
gcc -c stereo.c -Wall `pkg-config opencv --cflags` -lm -lpthread -lfftw3 -lfftw3_threads
|
||||||
|
|
||||||
|
bmp : bmp.c
|
||||||
|
gcc -o bmp bmp.c
|
75
sobel.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
unsigned char** Sobel(unsigned char*** image, int width, int height)
|
||||||
|
//cf. http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.html#sobel-derivatives and https://fr.wikipedia.org/wiki/Algorithme_de_Sobel
|
||||||
|
{
|
||||||
|
unsigned char** sobel;
|
||||||
|
int x,y,i;
|
||||||
|
unsigned char tempx, tempy;
|
||||||
|
|
||||||
|
if((sobel = malloc(sizeof(*sobel) * height)) == NULL)
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for(y = 0; y <= height; y++)
|
||||||
|
{
|
||||||
|
if((sobel[y] = malloc(sizeof(**sobel) * width)) == NULL)
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for(x = 0; x <= width; x++)
|
||||||
|
{
|
||||||
|
sobel[y][x] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(y = 1; y < height; y++)
|
||||||
|
{
|
||||||
|
for(x = 1; x < width; x++)
|
||||||
|
{
|
||||||
|
tempx = -image[y-1][x-1]+image[y-1][x+1]-2*image[y][x-1]+2*image[y][x+1]-image[y+1][x-1]+image[y+1][x+1];
|
||||||
|
tempy = -image[y-1][x-1]-2*image[y-1][x]-image[y-1][x+1]+image[y+1][x-1]+2*image[y+1][x]+image[y+1][x+1];
|
||||||
|
sobel[y][x] = (int) floor(sqrt(tempx^2 + tempy^2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sobel;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char*** add2images(unsigned char*** image1, unsigned char*** image2, int width, int height, int nChannels)
|
||||||
|
{
|
||||||
|
unsigned char*** sum;
|
||||||
|
int x,y,i;
|
||||||
|
|
||||||
|
if((sum = malloc(sizeof(*sum) * height)) == NULL)
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for(y = 0; y <= height; y++)
|
||||||
|
{
|
||||||
|
if((sum[y] = malloc(sizeof(**sum) * width)) == NULL)
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(y = 0; y <= height; y++)
|
||||||
|
{
|
||||||
|
for(x = 0; x <= width; x++)
|
||||||
|
{
|
||||||
|
if((sum[y][x] = malloc(sizeof(***sum) * nChannels)) == NULL) //sum[y][x][R,G,B]
|
||||||
|
{
|
||||||
|
perror("malloc:");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for(i = 0; i < nChannels; i++)
|
||||||
|
{
|
||||||
|
sum[y][x] = (unsigned char) ((image1[y][x][i] + image2[y][x][i])/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|