692 lines
21 KiB
C++
692 lines
21 KiB
C++
/*
|
|
Module d'interface utilisateur pour Astico2D :
|
|
Atelier Simple de Transformations d'Images au Clavier avec OpenCV en 2D
|
|
|
|
CC BY-SA Edouard.Thiel@univ-amu.fr - 04/09/2021 - v1.0
|
|
*/
|
|
|
|
#include "astico2d.hpp"
|
|
|
|
|
|
//---------------------------- C O U L E U R S --------------------------------
|
|
|
|
void representer_en_couleurs_vga (cv::Mat &img_niv, cv::Mat &img_coul)
|
|
{
|
|
CHECK_MAT_TYPE(img_niv, CV_32SC1);
|
|
CHECK_MAT_TYPE(img_coul, CV_8UC3);
|
|
|
|
unsigned char couls[16][3] = { // R, G, B
|
|
{ 0, 0, 0 }, // 0 black -> 0 uniquement
|
|
{ 30, 30, 230 }, // 1 blue -> 1, 15, 29, ...
|
|
{ 30, 200, 30 }, // 2 green -> 2, 16, 30, ...
|
|
{ 30, 200, 200 }, // 3 cyan -> 3, 17, 31, ...
|
|
{ 200, 30, 30 }, // 4 red -> 4, 18, 32, ...
|
|
{ 200, 30, 200 }, // 5 magenta -> 5, 19, 33, ...
|
|
{ 200, 130, 50 }, // 6 brown -> 6, 20, 34, ...
|
|
{ 200, 200, 200 }, // 7 light gray -> 7, 21, 35, ...
|
|
{ 110, 110, 140 }, // 8 dark gray -> 8, 22, 36, ...
|
|
{ 84, 130, 252 }, // 9 light blue -> 9, 23, 37, ...
|
|
{ 84, 252, 84 }, // 10 light green -> 10, 24, 38, ...
|
|
{ 84, 252, 252 }, // 11 light cyan -> 11, 25, 39, ...
|
|
{ 252, 84, 84 }, // 12 light red -> 12, 26, 40, ...
|
|
{ 252, 84, 252 }, // 13 light magenta -> 13, 27, 41, ...
|
|
{ 252, 252, 84 }, // 14 yellow -> 14, 28, 42, ...
|
|
{ 252, 252, 252 }, // 15 white -> 255 uniquement
|
|
};
|
|
|
|
for (int y = 0; y < img_niv.rows; y++)
|
|
for (int x = 0; x < img_niv.cols; x++)
|
|
{
|
|
int g = img_niv.at<int>(y,x), c = 0;
|
|
if (g == 255) c = 15; // seul 255 est blanc
|
|
else if (g != 0) c = 1 + abs(g-1) % 14; // seul 0 est noir
|
|
// Attention img_coul est en B, G, R -> inverser les canaux
|
|
img_coul.at<cv::Vec3b>(y,x)[0] = couls[c][2];
|
|
img_coul.at<cv::Vec3b>(y,x)[1] = couls[c][1];
|
|
img_coul.at<cv::Vec3b>(y,x)[2] = couls[c][0];
|
|
}
|
|
}
|
|
|
|
|
|
void inverser_couleurs (cv::Mat &img)
|
|
{
|
|
CHECK_MAT_TYPE(img, CV_8UC3);
|
|
|
|
for (int y = 0; y < img.rows; y++)
|
|
for (int x = 0; x < img.cols; x++)
|
|
{
|
|
img.at<cv::Vec3b>(y,x)[0] = 255 - img.at<cv::Vec3b>(y,x)[0];
|
|
img.at<cv::Vec3b>(y,x)[1] = 255 - img.at<cv::Vec3b>(y,x)[1];
|
|
img.at<cv::Vec3b>(y,x)[2] = 255 - img.at<cv::Vec3b>(y,x)[2];
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------- L O U P E ---------------------------------
|
|
|
|
void Loupe::reborner (cv::Mat &res1, cv::Mat &res2)
|
|
{
|
|
int bon_zoom = zoom >= 1 ? zoom : 1;
|
|
|
|
int h = res2.rows / bon_zoom;
|
|
int w = res2.cols / bon_zoom;
|
|
|
|
if (zoom_x0 < 0) zoom_x0 = 0;
|
|
zoom_x1 = zoom_x0 + w;
|
|
if (zoom_x1 > res1.cols) {
|
|
zoom_x1 = res1.cols;
|
|
zoom_x0 = zoom_x1 - w;
|
|
if (zoom_x0 < 0) zoom_x0 = 0;
|
|
}
|
|
|
|
if (zoom_y0 < 0) zoom_y0 = 0;
|
|
zoom_y1 = zoom_y0 + h;
|
|
if (zoom_y1 > res1.rows) {
|
|
zoom_y1 = res1.rows;
|
|
zoom_y0 = zoom_y1 - h;
|
|
if (zoom_y0 < 0) zoom_y0 = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void Loupe::deplacer (cv::Mat &res1, cv::Mat &res2, int dx, int dy)
|
|
{
|
|
zoom_x0 += dx; zoom_y0 += dy;
|
|
zoom_x1 += dx; zoom_y1 += dy;
|
|
reborner (res1, res2);
|
|
}
|
|
|
|
|
|
int Loupe::calculer_zoom_optimal (cv::Mat &src)
|
|
{
|
|
// On autorise l'image à dépasser de 10%
|
|
int zh = opt_h * 110 / (src.rows * 100),
|
|
zw = opt_w * 110 / (src.cols * 100);
|
|
int z = zh < zw ? zh : zw;
|
|
if (z < 1) z = 1; else if (z > zoom_max) z = zoom_max;
|
|
return z;
|
|
}
|
|
|
|
|
|
void Loupe::calculer_portion_optimale (cv::Mat &src, int &ph, int &pw)
|
|
{
|
|
ph = ((src.rows * zoom - 1) / vue_inc +1) * vue_inc;
|
|
pw = ((src.cols * zoom - 1) / vue_inc +1) * vue_inc;
|
|
if (ph < vue_min) ph = vue_min; else if (ph > opt_h) ph = opt_h;
|
|
if (pw < vue_min) pw = vue_min; else if (pw > opt_w) pw = opt_w;
|
|
}
|
|
|
|
|
|
void Loupe::dessiner_rect (cv::Mat &src, cv::Mat &dest)
|
|
{
|
|
dest = src.clone();
|
|
if (zoom == 0) return;
|
|
cv::Point p0 = cv::Point(zoom_x0, zoom_y0),
|
|
p1 = cv::Point(zoom_x1, zoom_y1);
|
|
cv::rectangle(dest, p0, p1, cv::Scalar (255, 255, 255), 3, 4);
|
|
cv::rectangle(dest, p0, p1, cv::Scalar ( 0, 0, 255), 1, 4);
|
|
}
|
|
|
|
|
|
void Loupe::dessiner_portion (cv::Mat &src, cv::Mat &dest)
|
|
{
|
|
CHECK_MAT_TYPE(src, CV_8UC3);
|
|
|
|
int bon_zoom = zoom >= 1 ? zoom : 1;
|
|
|
|
for (int y = 0; y < dest.rows; y++)
|
|
for (int x = 0; x < dest.cols; x++)
|
|
{
|
|
int x0 = zoom_x0 + x / bon_zoom;
|
|
int y0 = zoom_y0 + y / bon_zoom;
|
|
|
|
if (x0 < 0 || x0 >= src.cols || y0 < 0 || y0 >= src.rows) {
|
|
dest.at<cv::Vec3b>(y,x)[0] = 64;
|
|
dest.at<cv::Vec3b>(y,x)[1] = 64;
|
|
dest.at<cv::Vec3b>(y,x)[2] = 64;
|
|
continue;
|
|
}
|
|
dest.at<cv::Vec3b>(y,x)[0] = src.at<cv::Vec3b>(y0,x0)[0];
|
|
dest.at<cv::Vec3b>(y,x)[1] = src.at<cv::Vec3b>(y0,x0)[1];
|
|
dest.at<cv::Vec3b>(y,x)[2] = src.at<cv::Vec3b>(y0,x0)[2];
|
|
}
|
|
}
|
|
|
|
|
|
void Loupe::afficher_tableau_niveaux (cv::Mat &src, int ex, int ey, int rx, int ry)
|
|
{
|
|
CHECK_MAT_TYPE(src, CV_32SC1);
|
|
|
|
int bon_zoom = zoom >= 1 ? zoom : 1;
|
|
int cx = zoom_x0 + ex / bon_zoom;
|
|
int cy = zoom_y0 + ey / bon_zoom;
|
|
int x1 = cx-rx, x2 = cx+rx, y1 = cy-ry, y2 = cy+ry;
|
|
|
|
int vmin = 0, vmax = 0;
|
|
for (int y = y1; y <= y2; y++) {
|
|
for (int x = x1; x <= x2; x++) {
|
|
if (x < 0 || x >= src.cols || y < 0 || y >= src.rows)
|
|
continue;
|
|
int v = src.at<int>(y,x);
|
|
if (v < vmin) vmin = v;
|
|
else if (v > vmax) vmax = v;
|
|
}
|
|
}
|
|
int n1 = ceil(log10(abs(vmin)+1)), n2 = ceil(log10(abs(vmax)+1));
|
|
if (vmin < 0) n1++; // signe
|
|
if (vmax < 0) n2++;
|
|
int n = std::max(n1,n2); // nb de chiffres
|
|
|
|
std::cout << "Valeurs autour de " << cx << "," << cy << " :" << std::endl;
|
|
|
|
for (int y = y1; y <= y2; y++) {
|
|
for (int x = x1; x <= x2; x++) {
|
|
if (x < 0 || x >= src.cols || y < 0 || y >= src.rows)
|
|
std::cout << std::setw(n+1) << "* " ; // hors de l'image
|
|
else std::cout << std::setw(n) << src.at<int>(y,x) << " ";
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
|
|
void Loupe::afficher_tableau_couleurs (cv::Mat &src, int ex, int ey, int rx, int ry)
|
|
{
|
|
CHECK_MAT_TYPE(src, CV_8UC3);
|
|
|
|
int bon_zoom = zoom >= 1 ? zoom : 1;
|
|
int cx = zoom_x0 + ex / bon_zoom;
|
|
int cy = zoom_y0 + ey / bon_zoom;
|
|
int x1 = cx-rx, x2 = cx+rx, y1 = cy-ry, y2 = cy+ry;
|
|
|
|
int n = 3; // nb de chiffres
|
|
|
|
std::cout << "Valeurs autour de " << cx << "," << cy << " :" << std::endl;
|
|
|
|
for (int y = y1; y <= y2; y++) {
|
|
for (int x = x1; x <= x2; x++) {
|
|
if (x < 0 || x >= src.cols || y < 0 || y >= src.rows)
|
|
// hors de l'image
|
|
std::cout << "("
|
|
<< std::setw(n) << "* " << ","
|
|
<< std::setw(n) << "* " << ","
|
|
<< std::setw(n) << "* " << ") ";
|
|
else {
|
|
int cR = src.at<cv::Vec3b>(y,x)[2],
|
|
cV = src.at<cv::Vec3b>(y,x)[1],
|
|
cB = src.at<cv::Vec3b>(y,x)[0];
|
|
std::cout << "("
|
|
<< std::setw(n) << cR << ","
|
|
<< std::setw(n) << cV << ","
|
|
<< std::setw(n) << cB << ") ";
|
|
}
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
|
|
//----------------------------- A S T I C O 2 D -------------------------------
|
|
|
|
|
|
Astico2D::Astico2D (int &argc, char **&argv) : temps()
|
|
{
|
|
if (analyser_arguments (argc, argv) != 0) { init_ok = false ; return; }
|
|
if (lire_image_entree () != 0) { init_ok = false ; return; }
|
|
creer_images_resultat ();
|
|
creer_fenetres ();
|
|
}
|
|
|
|
|
|
int Astico2D::run ()
|
|
{
|
|
if (! init_ok) return 1;
|
|
afficher_touches_clavier ();
|
|
traiter_evenements ();
|
|
return (enregistrer_image_resultat () == 0) ? 0 : 1;
|
|
}
|
|
|
|
|
|
void Astico2D::afficher_usage (const char *nom_prog) {
|
|
std::cout << "Usage: " << nom_prog
|
|
<< " [-mag w h] [-thr seuil] [-o image_res] image_src"
|
|
<< " [autres options]"
|
|
<< std::endl;
|
|
}
|
|
|
|
|
|
int Astico2D::analyser_arguments (int &argc, char **&argv)
|
|
{
|
|
nom_out2 = NULL;
|
|
|
|
char *nom_prog = argv[0];
|
|
argc -= 1; argv += 1;
|
|
|
|
while (argc > 0) {
|
|
if (!strcmp(argv[0], "-mag")) {
|
|
if (argc-1 < 3) { afficher_usage(nom_prog); return 1; }
|
|
zoom_w = atoi(argv[1]);
|
|
zoom_h = atoi(argv[2]);
|
|
argc -= 3; argv += 3;
|
|
} else if (!strcmp(argv[0], "-thr")) {
|
|
if (argc-1 < 2) { afficher_usage(nom_prog); return 1; }
|
|
seuil_niv = atoi(argv[1]);
|
|
argc -= 2; argv += 2;
|
|
} else if (!strcmp(argv[0], "-o")) {
|
|
if (argc-1 < 2) { afficher_usage(nom_prog); return 1; }
|
|
nom_out2 = argv[1];
|
|
argc -= 2; argv += 2;
|
|
} else break;
|
|
}
|
|
|
|
if (argc < 1) { afficher_usage(nom_prog); return 1; }
|
|
nom_in1 = argv[0];
|
|
argc -= 1; argv += 1;
|
|
|
|
// Les arguments supplémentaires restent dans argc,argv et peuvent être
|
|
// analysés dans le constructeur d'une classe fille après l'appel du
|
|
// constructeur de la classe mère.
|
|
return 0;
|
|
}
|
|
|
|
|
|
int Astico2D::lire_image_entree ()
|
|
{
|
|
img_src = cv::imread (nom_in1, cv::IMREAD_COLOR); // produit du 8UC3
|
|
if (img_src.empty()) {
|
|
std::cout << "Erreur de lecture de \"" << nom_in1 << "\","
|
|
<< " ou format incompatible de l'image." << std::endl;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int Astico2D::enregistrer_image_resultat ()
|
|
{
|
|
if (!nom_out2) return 0;
|
|
|
|
int res = cv::imwrite (nom_out2, img_coul);
|
|
if (res) std::cout << "Enregistrement reussi";
|
|
else std::cout << "Erreur d'enregistrement";
|
|
std::cout << " dans \"" << nom_out2 << "\"." << std::endl;
|
|
return res ? 0 : -1;
|
|
}
|
|
|
|
|
|
void Astico2D::creer_images_resultat ()
|
|
{
|
|
img_res1 = cv::Mat(img_src.rows, img_src.cols, CV_8UC3);
|
|
img_res2 = cv::Mat(zoom_h, zoom_w, CV_8UC3);
|
|
img_niv = cv::Mat(img_src.rows, img_src.cols, CV_32SC1);
|
|
img_coul = cv::Mat(img_src.rows, img_src.cols, CV_8UC3);
|
|
loupe.reborner(img_res1, img_res2);
|
|
}
|
|
|
|
|
|
void Astico2D::creer_slider (const char* nom_slider, int *valeur_courante,
|
|
int valeur_max)
|
|
{
|
|
cv::createTrackbar (nom_slider, "ImageSrc", valeur_courante, valeur_max,
|
|
onDefaultTrackbarSlide, this);
|
|
}
|
|
|
|
|
|
void Astico2D::modifier_slider (const char* nom_slider, int nouvelle_valeur)
|
|
{
|
|
cv::setTrackbarPos (nom_slider, "ImageSrc", nouvelle_valeur);
|
|
}
|
|
|
|
|
|
void Astico2D::diminuer_slider (const char* nom_slider, int valeur_min)
|
|
{
|
|
int nouv = cv::getTrackbarPos (nom_slider, "ImageSrc") - 1;
|
|
if (nouv >= valeur_min) modifier_slider (nom_slider, nouv);
|
|
}
|
|
|
|
|
|
void Astico2D::augmenter_slider (const char* nom_slider, int valeur_max)
|
|
{
|
|
int nouv = cv::getTrackbarPos (nom_slider, "ImageSrc") + 1;
|
|
if (nouv <= valeur_max) modifier_slider (nom_slider, nouv);
|
|
}
|
|
|
|
|
|
void Astico2D::creer_fenetres ()
|
|
{
|
|
cv::namedWindow ("ImageSrc", cv::WINDOW_AUTOSIZE);
|
|
cv::createTrackbar ("Zoom", "ImageSrc", &loupe.zoom, loupe.zoom_max,
|
|
onZoomSlide, this);
|
|
creer_slider ("Seuil", &seuil_niv, seuil_max);
|
|
cv::setMouseCallback ("ImageSrc", onMouseEventSrc, this);
|
|
|
|
cv::namedWindow ("Loupe", cv::WINDOW_AUTOSIZE);
|
|
cv::setMouseCallback ("Loupe", onMouseEventLoupe, this);
|
|
}
|
|
|
|
|
|
void Astico2D::traiter_evenements ()
|
|
{
|
|
for (;;) {
|
|
|
|
if (recalc == R_TOUTES)
|
|
{
|
|
if (mode_transfo == M_NIVEAUX) {
|
|
//std::cout << "Calcul img_niv" << std::endl;
|
|
cv::Mat img_gry;
|
|
cv::cvtColor (img_src, img_gry, cv::COLOR_BGR2GRAY);
|
|
cv::threshold (img_gry, img_gry, seuil_niv, 255, cv::THRESH_BINARY);
|
|
img_gry.convertTo (img_niv, CV_32SC1,1., 0.);
|
|
} else {
|
|
img_coul = img_src.clone();
|
|
}
|
|
|
|
if (mode_transfo != M_AUCUN && touche_transfo != 0) {
|
|
//std::cout << "Calcul tranformations pour '"
|
|
// << char(touche_transfo) << "'" << std::endl;
|
|
double t1 = temps.mesurer ();
|
|
// RQ : cet appel doit produire une image couleur dans img_coul.
|
|
effectuer_transformations ();
|
|
double t2 = temps.mesurer ();
|
|
if (MESURER_TEMPS) {
|
|
std::cout << "Duree transformations : "
|
|
<< std::to_string(t2-t1) << " s" << std::endl;
|
|
}
|
|
} else if (mode_transfo == M_NIVEAUX) {
|
|
representer_en_couleurs_vga (img_niv, img_coul);
|
|
}
|
|
}
|
|
|
|
if (recalc == R_TOUTES || recalc == R_LOUPE) {
|
|
//std::cout << "Calcul images loupe" << std::endl;
|
|
loupe.dessiner_rect (img_coul, img_res1);
|
|
loupe.dessiner_portion (img_coul, img_res2);
|
|
cv::imshow ("ImageSrc", img_res1);
|
|
cv::imshow ("Loupe" , img_res2);
|
|
}
|
|
|
|
recalc = R_RIEN;
|
|
|
|
// Attente du prochain événement sur toutes les fenêtres, avec un
|
|
// timeout de 15ms pour détecter les changements de flags
|
|
int key = cv::waitKey (15);
|
|
|
|
// Gestion des événements clavier avec une callback "maison" que l'on
|
|
// appelle nous-même. Les Callbacks souris et slider sont directement
|
|
// appelées par waitKey lors de l'attente.
|
|
if (onKeyPressEvent (key, this) < 0) break;
|
|
}
|
|
}
|
|
|
|
|
|
// Callbacks des sliders
|
|
|
|
void Astico2D::onZoomSlide (int pos, void *data)
|
|
{
|
|
Astico2D *ao = (Astico2D*) data;
|
|
ao->loupe.reborner (ao->img_res1, ao->img_res2);
|
|
ao->recalc = R_LOUPE;
|
|
}
|
|
|
|
void Astico2D::onDefaultTrackbarSlide (int pos, void *data)
|
|
{
|
|
Astico2D *ao = (Astico2D*) data;
|
|
ao->recalc = R_TOUTES;
|
|
}
|
|
|
|
|
|
// Callback pour la souris
|
|
|
|
void Astico2D::onMouseEventSrc (int event, int x, int y, int flags, void *data)
|
|
{
|
|
Astico2D *ao = (Astico2D*) data;
|
|
switch (event) {
|
|
case cv::EVENT_LBUTTONDOWN :
|
|
ao->clic_x = x;
|
|
ao->clic_y = y;
|
|
ao->clic_n = 1;
|
|
break;
|
|
case cv::EVENT_MOUSEMOVE :
|
|
// std::cout << "mouse move " << x << "," << y << std::endl;
|
|
if (ao->clic_n == 1) {
|
|
ao->loupe.deplacer (ao->img_res1, ao->img_res2,
|
|
x - ao->clic_x, y - ao->clic_y);
|
|
ao->clic_x = x;
|
|
ao->clic_y = y;
|
|
ao->recalc = R_LOUPE;
|
|
}
|
|
break;
|
|
case cv::EVENT_LBUTTONUP :
|
|
ao->clic_n = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void Astico2D::onMouseEventLoupe (int event, int x, int y, int flags, void *data)
|
|
{
|
|
Astico2D *ao = (Astico2D*) data;
|
|
switch (event) {
|
|
case cv::EVENT_LBUTTONDOWN :
|
|
if (ao->mode_transfo == M_NIVEAUX)
|
|
ao->loupe.afficher_tableau_niveaux (ao->img_niv, x, y, 5, 4);
|
|
else ao->loupe.afficher_tableau_couleurs (ao->img_coul, x, y, 2, 3);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Gestion du clavier
|
|
|
|
void Astico2D::afficher_touches_clavier ()
|
|
{
|
|
std::cout <<
|
|
"Touches du clavier :\n"
|
|
" a affiche cette aide\n"
|
|
" Esc quitte (et enregistre image_res)\n"
|
|
" hHlL change la hauteur ou largeur de la loupe\n"
|
|
" jJkK deplace la loupe\n"
|
|
" zZ change le zoom\n"
|
|
" g agrandit la loupe et adapte le zoom\n"
|
|
" i inverse les couleurs de l'image d'origine\n"
|
|
" os affiche l'image d'origine ou seuillee\n"
|
|
" eE change le seuil\n";
|
|
}
|
|
|
|
|
|
int Astico2D::onKeyPressEvent (int key, void *data)
|
|
{
|
|
Astico2D *ao = (Astico2D*) data;
|
|
if (key < 0) return 0; // aucune touche pressée
|
|
key &= 255; // pour comparer avec un char
|
|
|
|
switch (key) {
|
|
case 'a' :
|
|
ao->afficher_touches_clavier();
|
|
break;
|
|
case 27 : // ESC pour quitter
|
|
return -1;
|
|
case 'h' :
|
|
case 'H' :
|
|
case 'l' :
|
|
case 'L' : {
|
|
int h = ao->img_res2.rows, w = ao->img_res2.cols,
|
|
a = ao->loupe.vue_min, b = ao->loupe.vue_max,
|
|
i = ao->loupe.vue_inc;
|
|
if (key == 'h') h = (h >= a+i) ? h-i : a;
|
|
else if (key == 'H') h = (h <= b-i) ? h+i : b;
|
|
else if (key == 'l') w = (w >= a+i) ? w-i : a;
|
|
else if (key == 'L') w = (w <= b-i) ? w+i : b;
|
|
std::cout << "Taille loupe " << w << "x" << h << std::endl;
|
|
ao->img_res2 = cv::Mat(h, w, CV_8UC3);
|
|
ao->loupe.reborner(ao->img_res1, ao->img_res2);
|
|
ao->recalc = R_LOUPE;
|
|
break;
|
|
}
|
|
case 'j' :
|
|
ao->loupe.deplacer (ao->img_res1, ao->img_res2, 0, -1);
|
|
ao->recalc = R_LOUPE;
|
|
break;
|
|
case 'J' :
|
|
ao->loupe.deplacer (ao->img_res1, ao->img_res2, 0, 1);
|
|
ao->recalc = R_LOUPE;
|
|
break;
|
|
case 'k' :
|
|
ao->loupe.deplacer (ao->img_res1, ao->img_res2, -1, 0);
|
|
ao->recalc = R_LOUPE;
|
|
break;
|
|
case 'K' :
|
|
ao->loupe.deplacer (ao->img_res1, ao->img_res2, 1, 0);
|
|
ao->recalc = R_LOUPE;
|
|
break;
|
|
case 'z' :
|
|
ao->diminuer_slider ("Zoom", 1);
|
|
break;
|
|
case 'Z' :
|
|
ao->augmenter_slider ("Zoom", ao->loupe.zoom_max);
|
|
break;
|
|
case 'g' : {
|
|
int z = ao->loupe.calculer_zoom_optimal (ao->img_src);
|
|
ao->modifier_slider ("Zoom", z);
|
|
int ph, pw;
|
|
ao->loupe.calculer_portion_optimale (ao->img_src, ph, pw);
|
|
std::cout << "Taille loupe " << pw << "x" << ph
|
|
<<" zoom " << z << std::endl;
|
|
ao->img_res2 = cv::Mat(ph, pw, CV_8UC3);
|
|
ao->loupe.reborner(ao->img_res1, ao->img_res2);
|
|
ao->recalc = R_LOUPE;
|
|
break;
|
|
}
|
|
case 'i' :
|
|
std::cout << "Couleurs inversees" << std::endl;
|
|
inverser_couleurs(ao->img_src);
|
|
ao->recalc = R_TOUTES;
|
|
break;
|
|
case 'o' :
|
|
std::cout << "Image originale" << std::endl;
|
|
ao->recalc = R_TOUTES;
|
|
ao->mode_transfo = M_AUCUN;
|
|
break;
|
|
case 's' :
|
|
std::cout << "Image seuillee" << std::endl;
|
|
ao->recalc = R_TOUTES;
|
|
ao->mode_transfo = M_NIVEAUX;
|
|
ao->touche_transfo = 0;
|
|
break;
|
|
case 'e' :
|
|
ao->diminuer_slider ("Seuil", 0);
|
|
break;
|
|
case 'E' :
|
|
ao->augmenter_slider ("Seuil", ao->seuil_max);
|
|
break;
|
|
|
|
default :
|
|
if (ao->traiter_touche_clavier (key)) {
|
|
ao->recalc = R_TOUTES;
|
|
}
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
//------------------------ M E S U R E T E M P S ----------------------------
|
|
|
|
// Mesure du temps.
|
|
// Code extrait de EZ-Draw version 1.2 (LGPL), Edouard.Thiel@univ-amu.fr
|
|
|
|
#if MESURER_TEMPS
|
|
|
|
MesureTemps::MesureTemps ()
|
|
{
|
|
# ifdef _WIN32
|
|
_init_timeofday ();
|
|
# endif
|
|
}
|
|
|
|
|
|
// Return the elapsed time since the Epoch in seconds,microseconds
|
|
double MesureTemps::mesurer ()
|
|
{
|
|
struct timeval tp;
|
|
_gettimeofday (&tp);
|
|
return (double) tp.tv_sec + (double) tp.tv_usec / (double) 1E6;
|
|
}
|
|
|
|
|
|
# ifdef _WIN32
|
|
|
|
// Initialize time computation.
|
|
|
|
void MesureTemps::_init_timeofday (void)
|
|
{
|
|
LARGE_INTEGER freq;
|
|
|
|
_perf_freq = 0;
|
|
_get_systemtime (&_start_time);
|
|
QueryPerformanceCounter (&_start_count);
|
|
|
|
if (QueryPerformanceFrequency (&freq) && freq.QuadPart > 0)
|
|
_perf_freq = 1.0 / freq.QuadPart;
|
|
}
|
|
|
|
|
|
// Emulate gettimeofday() with GetSystemTimeAsFileTime().
|
|
// GetSystemTimeAsFileTime() has an accuracy of 15ms (10ms on XP).
|
|
// GetSystemTimePreciseAsFileTime() has an accuracy of 1ms but needs
|
|
// windows >= 8, and seems rather expensive.
|
|
|
|
void MesureTemps::_get_systemtime (struct timeval *t)
|
|
{
|
|
ULARGE_INTEGER ul;
|
|
FILETIME ft;
|
|
double dt;
|
|
if (t == NULL) return;
|
|
GetSystemTimeAsFileTime (&ft);
|
|
ul.LowPart = ft.dwLowDateTime;
|
|
ul.HighPart = ft.dwHighDateTime;
|
|
dt = ul.QuadPart / 10000000.0 - 11644473600.0;
|
|
t->tv_sec = dt;
|
|
t->tv_usec = (dt - t->tv_sec) * 1000000.0;
|
|
}
|
|
|
|
|
|
// Emulate gettimeofday() with QueryPerformanceCounter().
|
|
// This method seems to be more accurate than _get_systemtime()
|
|
// but leads to a drift.
|
|
|
|
void MesureTemps::_get_countertime (struct timeval *t)
|
|
{
|
|
LARGE_INTEGER now;
|
|
double dt;
|
|
QueryPerformanceCounter (&now);
|
|
dt = (now.QuadPart - _start_count.QuadPart) * _perf_freq;
|
|
*t = _start_time;
|
|
t->tv_sec += dt;
|
|
t->tv_usec += (dt - (int)dt) * 1000000;
|
|
t->tv_sec += t->tv_usec / 1000000;
|
|
t->tv_usec %= 1000000;
|
|
}
|
|
|
|
# endif // _WIN32
|
|
|
|
|
|
// Compute elapsed time since the Epoch.
|
|
|
|
void MesureTemps::_gettimeofday (struct timeval *t)
|
|
{
|
|
if (t == NULL) return;
|
|
#ifdef _WIN32
|
|
if (_perf_freq == 0)
|
|
_get_systemtime (t);
|
|
else _get_countertime (t);
|
|
#else
|
|
gettimeofday (t, NULL);
|
|
#endif
|
|
}
|
|
|
|
#endif // MESURER_TEMPS
|
|
|