Traitement d'images avancé C++ OpenCV

Le traitement avancé d'images consiste à effectuer des tâches plus complexes sur la base du traitement d'images de base (comme le filtrage, la détection de contours, etc.), telles que la segmentation d'images, la détection de contours, les opérations morphologiques, le traitement d'histogrammes, et plus encore. Ces techniques sont largement utilisées dans des domaines tels que la détection d'objets, l'analyse d'images et le traitement d'images médicales.

Scénarios d'application du traitement avancé d'images

Analyse d'images médicales :

  • Utiliser des techniques de segmentation d'images pour extraire les régions lésionnelles.

  • Utiliser des opérations morphologiques pour supprimer le bruit.

Détection et suivi d'objets :

  • Utiliser la détection de contours et la correspondance de modèles pour localiser des objets.

  • Utiliser le traitement d'histogrammes pour améliorer les caractéristiques des objets.

Amélioration d'images :

  • Utiliser l'égalisation d'histogrammes pour améliorer le contraste de l'image.

  • Utilisez l'algorithme watershed pour séparer des objets qui se chevauchent.


Segmentation d'image

La segmentation d'image est une étape importante du traitement d'image. Elle divise une image en plusieurs régions ou objets pour une analyse et un traitement ultérieurs. Les méthodes courantes de segmentation d'image comprennent la segmentation par seuillage, la segmentation par contours et la segmentation par régions.

Segmentation par seuillage

La segmentation par seuillage est l'une des méthodes de segmentation d'image les plus simples. Elle classe les valeurs de pixels en différentes catégories en définissant un ou plusieurs seuils. Les méthodes courantes de segmentation par seuillage comprennent le seuillage global et le seuillage adaptatif.

Seuillage global

Le seuillage global utilise un seuil fixe pour diviser une image en premier plan et arrière-plan. OpenCV fournit lacv::thresholdfonction pour implémenter cela.

cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat dst;
cv::threshold(src, dst, 128, 255, cv::THRESH_BINARY);

Dans le code ci-dessus,128est le seuil,255est la valeur maximale des pixels,cv::THRESH_BINARYindique l'utilisation de la méthode de seuillage binaire.

Seuillage adaptatif

Le seuillage adaptatif ajuste dynamiquement le seuil en fonction des régions locales de l'image. OpenCV fournit lacv::adaptiveThresholdfonction pour implémenter cela.

cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat dst;
cv::adaptiveThreshold(src, dst, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 11, 2);

Dans le code ci-dessus,255est la valeur maximale des pixels,cv::ADAPTIVE_THRESH_MEAN_Cindique l'utilisation de la moyenne locale comme seuil,11est la taille du voisinage,2est la constante.

Segmentation basée sur les contours

La segmentation basée sur les contours segmente une image en détectant les contours dans l'image. Les algorithmes courants de détection de contours incluent la détection de contours de Canny et l'opérateur Sobel.

Détection de contours de Canny

La détection de contours de Canny est un algorithme de détection de contours à plusieurs étapes. OpenCV fournit lacv::Cannyfonction pour implémenter cela.

cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat edges;
cv::Canny(src, edges, 100, 200);

Dans le code ci-dessus,100et200sont les deux seuils de l'algorithme de Canny.

Segmentation basée sur les régions (algorithme de ligne de partage des eaux)

La segmentation basée sur les régions réalise la segmentation en divisant l'image en plusieurs régions. L'algorithme de ligne de partage des eaux est une méthode de segmentation basée sur les régions couramment utilisée.

Algorithme de ligne de partage des eaux

L'algorithme de ligne de partage des eaux traite l'image comme une carte topographique et la segmente en simulant la diffusion du flux d'eau. OpenCV fournit lacv::watershedfonction pour implémenter cela.

cv::Mat src = cv::imread("image.jpg");
cv::Mat markers = cv::Mat::zeros(src.size(), CV_32S);
cv::watershed(src, markers);

Dans le code ci-dessus,markersest la matrice de marqueurs, utilisée pour stocker le résultat de la segmentation.


Détection de contours

La détection de contours est une étape importante du traitement d'images. Elle est utilisée pour détecter les limites des objets dans une image. OpenCV fournit diverses fonctions pour la détection et le traitement des contours.

Recherche de contours

La recherche des contours est la première étape de la détection de contours. OpenCV fournit lacv::findContoursfonction pour implémenter cela.

cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(src, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

Dans le code ci-dessus,contoursest le vecteur qui stocke les contours,hierarchyest le vecteur qui stocke la hiérarchie des contours.

Caractéristiques des contours

Les caractéristiques des contours incluent l'aire, le périmètre, la boîte englobante, et plus encore. OpenCV fournit diverses fonctions pour calculer ces caractéristiques.

Zone

L'aire est une caractéristique importante d'un contour. OpenCV fournit lacv::contourAreafonction pour calculer l'aire d'un contour.

double area = cv::contourArea(contours[0]);

Perimeter

Le périmètre est une autre caractéristique importante d'un contour. OpenCV fournit lacv::arcLengthfonction pour calculer le périmètre d'un contour.

double perimeter = cv::arcLength(contours[0], true);

Boîte englobante

Une boîte englobante est le plus petit rectangle englobant d'un contour. OpenCV fournit lacv::boundingRectfonction pour calculer la boîte englobante.

cv::Rect rect = cv::boundingRect(contours[0]);

Dessin des contours

Le dessin des contours consiste à dessiner les contours détectés sur une image. OpenCV fournit lacv::drawContoursfonction pour implémenter cela.

cv::Mat dst = cv::Mat::zeros(src.size(), CV_8UC3);
cv::drawContours(dst, contours, -1, cv::Scalar(0, 255, 0), 2);

Dans le code ci-dessus,dstest l'image après le dessin des contours,cv::Scalar(0, 255, 0)est la couleur des contours,2est la largeur de ligne des contours.


Correspondance de modèle

La correspondance de modèle est une méthode permettant de trouver un modèle spécifique dans une image. OpenCV fournit lacv::matchTemplatefonction pour implémenter cela.

Correspondance de modèle simple

La correspondance de modèle unique consiste à trouver un modèle dans une image. OpenCV fournit lacv::matchTemplatefonction pour implémenter cela.

cv::Mat src = cv::imread("image.jpg");
cv::Mat templ = cv::imread("template.jpg");
cv::Mat result;
cv::matchTemplate(src, templ, result, cv::TM_CCOEFF_NORMED);

Dans le code ci-dessus,resultest la matrice de résultat de correspondance,cv::TM_CCOEFF_NORMEDest la méthode de correspondance.

Correspondance de modèles multiples

La correspondance de modèles multiples consiste à trouver plusieurs modèles dans une image. Elle peut être implémentée en parcourant la matrice de résultat de correspondance.

double minVal, maxVal;
cv::Point minLoc, maxLoc;
cv::minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);

Dans le code ci-dessus,maxLocest la position de la valeur maximale dans le résultat de correspondance.


Exemple

Algorithme de ligne de partage des eaux

Exemple

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    // Lire l'image
    Mat image = imread("objects.jpg");
    if (image.empty()) {
        cout << "Erreur : Impossible de charger l'image. Veuillez vérifier si le chemin est correct." << endl;
        return -1;
    }

    // Convertir en niveaux de gris
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);

    // Binariser
    Mat binary;
    threshold(gray, binary, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);

    // Supprimer le bruit
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
    morphologyEx(binary, binary, MORPH_OPEN, kernel, Point(-1, -1), 2);

    // Calculer la transformée de distance
    Mat dist;
    distanceTransform(binary, dist, DIST_L2, 5);

    // Normaliser l'image de transformée de distance
    normalize(dist, dist, 0, 1.0, NORM_MINMAX);

    // Binariser l'image de transformée de distance
    threshold(dist, dist, 0.5, 1.0, THRESH_BINARY);

    // Trouver les contours
    Mat dist_8u;
    dist.convertTo(dist_8u, CV_8U);
    vector<vector<Point>> contours;
    findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    // Créer l'image de marqueurs
    Mat markers = Mat::zeros(dist.size(), CV_32S);
    for (size_t i = 0; i < contours.size(); i++) {
        drawContours(markers, contours, static_cast<int>(i), Scalar(static_cast<int>(i) + 1), -1);
    }

    // Appliquer l'algorithme watershed
    watershed(image, markers);

    // Afficher le résultat
    Mat result = image.clone();
    for (int i = 0; i < markers.lignes; i++) {
        for (int j = 0; j < markers.cols; j++) {
            if (markers.at<int>(i, j) == -1) {
                result.at<Vec3b>(i, j) = Vec3b(0, 255, 0); // Marquer les limites en vert
            }
        }
    }

    imshow("Résultat du watershed", result);
    waitKey(0);

    return 0;
}

Détection de contours

La détection de contours est utilisée pour extraire les limites des objets dans une image.

OpenCV fournit la fonction findContours pour détecter les contours.

Exemple

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    // Lire l'image
    Mat image = imread("objects.jpg");
    if (image.empty()) {
        cout << "Erreur : Impossible de charger l'image. Veuillez vérifier si le chemin est correct." << endl;
        return -1;
    }

    // Convertir en niveaux de gris
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);

    // Binariser
    Mat binary;
    threshold(gray, binary, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);

    // Trouver les contours
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);

    // Dessiner les contours
    Mat result = Mat::zeros(image.size(), CV_8UC3);
    for (size_t i = 0; i < contours.size(); i++) {
        drawContours(result, contours, i, Scalar(0, 255, 0), 2);
    }

    // Afficher le résultat
    imshow("Contours", result);
    waitKey(0);

    return 0;
}

Opérations morphologiques

Les opérations morphologiques sont des techniques de traitement d'image basées sur la forme, couramment utilisées pour éliminer le bruit, séparer les objets, et plus encore.

Exemple

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    // Lire l'image
    Mat image = imread("noisy_image.jpg");
    if (image.empty()) {
        cout << "Erreur : Impossible de charger l'image. Veuillez vérifier si le chemin est correct." << endl;
        return -1;
    }

    // Convertir en niveaux de gris
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);

    // Binariser
    Mat binary;
    threshold(gray, binary, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);

    // Définir le noyau
    Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));

    // Opération d'ouverture (éliminer le bruit)
    Mat opened;
    morphologyEx(binary, opened, MORPH_OPEN, kernel);

    // Opération de fermeture (combler les trous)
    Mat closed;
    morphologyEx(opened, closed, MORPH_CLOSE, kernel);

    // Afficher le résultat
    imshow("Binaire original", binary);
    imshow("Image ouverte", opened);
    imshow("Image fermée", closed);
    waitKey(0);

    return 0;
}

Traitement d'histogramme

Le traitement d'histogramme est utilisé pour analyser la distribution des pixels d'une image. Les opérations courantes incluent l'égalisation d'histogramme, l'appariement d'histogramme, et plus encore.

Exemple

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    // Lire l'image
    Mat image = imread("low_contrast.jpg");
    if (image.empty()) {
        cout << "Erreur : Impossible de charger l'image. Veuillez vérifier si le chemin est correct." << endl;
        return -1;
    }

    // Convertir en niveaux de gris
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);

    // Égalisation d'histogramme
    Mat equalized;
    equalizeHist(gray, equalized);

    // Afficher le résultat
    imshow("Image originale", gray);
    imshow("Image égalisée", equalized);
    waitKey(0);

    return 0;
}

Correspondance de modèle

La correspondance de modèles est utilisée pour trouver des régions dans une image qui sont similaires à un modèle.

Exemple


#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    // Lire l'image et le modèle
    Mat image = imread("scene.jpg");
    Mat templ = imread("template.jpg");
    if (image.empty() || templ.empty()) {
        cout << "Erreur : Impossible de charger l'image. Veuillez vérifier si le chemin est correct." << endl;
        return -1;
    }

    // Correspondance de modèles
    Mat result;
    matchTemplate(image, templ, result, TM_CCOEFF_NORMED);

    // Trouver la meilleure position de correspondance
    double minVal, maxVal;
    Point minLoc, maxLoc;
    minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);

    // Dessiner un rectangle
    rectangle(image, maxLoc, Point(maxLoc.x + templ.cols, maxLoc.y + templ.rows), Scalar(0, 255, 0), 2);

    // Afficher le résultat
    imshow("Correspondance de modèle", image);
    waitKey(0);

    return 0;
}
Autres extensions