Ensayo de creación de simios | Programación OpenCV: la entrada de la visión artificial

La visión por computadora es una ciencia que estudia cómo hacer que las máquinas "vean". Más específicamente, se refiere al uso de cámaras y computadoras en lugar de los ojos humanos para identificar, rastrear y medir objetivos, y el procesamiento adicional de imágenes para que el procesamiento de la computadora se convierta en Imágenes que son más adecuados para la observación humana o se transmiten a instrumentos para su detección. Como disciplina científica, la visión artificial estudia teorías y tecnologías relacionadas, tratando de construir sistemas de inteligencia artificial que puedan obtener "información" a partir de imágenes o datos multidimensionales.

Las imágenes y los videos son omnipresentes en el mundo digital actual y, con la llegada de dispositivos informáticos potentes y asequibles, crear aplicaciones de imágenes complejas nunca ha sido tan fácil. Existen numerosos software y bibliotecas en el mercado para manipular imágenes y videos, pero la biblioteca OpenCV es una herramienta imprescindible para cualquiera que busque desarrollar su propio software. OpenCV(Open Source Computer Vision)es una biblioteca de análisis de imágenes y videos de código abierto que contiene más de 500 algoritmos optimizados. Desde su inicio en 1999, ha sido considerado como la herramienta elegida por académicos y desarrolladores en el campo de la visión artificial. ¡Entremos juntos por la puerta de la visión artificial!

la imagen de contacto

Este capítulo lo guiará a través de las operaciones más básicas: lectura, visualización y almacenamiento de imágenes. Antes de comenzar el desarrollo, debe instalar la biblioteca y un IDE práctico. Se recomienda aquí VS o Qt. La visión artificial no está vinculada a un entorno o sistema operativo específico.

  • Módulo opencv_core: contiene funciones básicas, especialmente estructuras de datos de bajo nivel y funciones de algoritmo.
  • Módulo opencv_imgproc: Contiene funciones de procesamiento de imágenes.
  • Módulo opencv_highgui: Contiene funciones para leer y escribir imágenes y videos, y funciones para manipular interfaces gráficas de usuario.
  • Módulo opencv_features2d: contiene detectores de puntos de interés, descriptores y marcos de coincidencia de puntos de interés.

Comencemos leyendo la imagen que preparamos, luego configuremos la ventana y luego mostremos la imagen en la ventana, esperando que el usuario escriba para salir:

cv::Mat image = cv::imread("/home/dzh/QtOpenCV/image.png", 1);
cv::namedWindow("Image");
cv::imshow("Image", image);
cv::waitKey(0);

A continuación se muestra el método que escribí en la clase para leer todas las imágenes en la carpeta y mostrarlas una por una.

inserte la descripción de la imagen aquí

En segundo lugar, el funcionamiento del píxel.

Para escribir aplicaciones de visión artificial, debe acceder al contenido de las imágenes, como modificar y crear imágenes. Este capítulo le enseñará cómo manipular los píxeles básicos de una imagen, los llamados píxeles. Aprenderá cómo iterar sobre una imagen y manipular sus píxeles. Opencv usa la estructura de datos cv::Mat para representar el motivo de la imagen. Cada elemento de la matriz representa un píxel. Para las imágenes en escala de grises, los píxeles se representan mediante números sin signo de 8 bits, donde 0 representa el negro y 255 representa el blanco. Las imágenes en color requieren 3 canales de color.

Podemos usar punteros para recorrer la imagen, recorrer las operaciones de campo de la imagen, realizar operaciones de imagen simples y definir regiones de interés.

// 颜色缩减[指针遍历]
void MainWindow::colorReduce(cv::Mat &image, cv::Mat &result, int div) {
    
    
    // 行数
    int nl = image.rows;
    // 每行的元素个数(像素个数 x 通道数)
    int nc = image.cols * image.channels();
    // 左移位数
    int n = 0;
    // 遍历每一行
    for (int j = 0; j < nl; j++) {
    
    
        // 得到第j行的首地址
        uchar* data = image.ptr<uchar>(j);
        // 求解pow的反函数
        for (int k = 1; k <= 8; k++) {
    
    
            if (pow(2, k) == div) {
    
    
                n = k;
                break;
            } else if (pow(2, k) > div) {
    
    
                n = k - 1;
                break;
            }
        }
        // 掩码左移
        uchar mask = 0xFF << n;
        for (int i = 0; i < nc; i++) {
    
    
//            data[i] = data[i] / div * div + div / 2;
            data[i] = (data[i] & mask) + div / 2;
        }
    }
}

// 图像运算
void MainWindow::imageProc(cv::Mat &image1, cv::Mat &image2, cv::Mat &result) {
    
    
    result = image1 * 0.8 + image2 * 0.2;
}

// 感兴趣区域
void MainWindow::imageROI(cv::Mat &image1, cv::Mat &image2) {
    
    
    // 相当于截取图像的一个区域
    cv::Mat roi = image1(cv::Rect(280, 260, image2.cols, image2.rows));
    cv::addWeighted(roi, 0.2, image2, 0.8, 0.1, roi);

}

3. Procesamiento de imágenes basado en clases

La calidad de un programa de visión artificial está íntimamente relacionada con las buenas prácticas de programación. Crear una aplicación libre de errores es solo el comienzo, esperamos que la aplicación pueda hacer frente fácilmente a los nuevos requisitos. Los patrones de diseño son conceptos bien conocidos en ingeniería de software. Un patrón de diseño es una solución confiable y reutilizable para los problemas que ocurren con frecuencia en el diseño de software. El primero es el patrón de estrategia, que usa controladores para implementar la comunicación entre módulos, usa el patrón de diseño singleton y usa la arquitectura MVC para diseñar aplicaciones.

void Histogram1D::process() {
    
    
    cv::Mat image = cv::imread("/home/dzh/QtOpenCV/image.png");
    if (!image.data) {
    
    
        cout << "图像不存在" << endl;
        return;
    } else {
    
    
        cout << "图像的宽度:" << image.cols << "图像的高度:" << image.rows << "像素总数:" << image.cols * image.rows << endl;
    }
    Histogram1D hc;
    cv::Mat imageROI; // 获取感兴趣区域
    imageROI = image(cv::Rect(160, 300, 100, 120));
    int minSat = 65;  // 彩色直方图
    cv::MatND colorhist = hc.getHueHistogram(imageROI, minSat);
    ContentFinder finder;
    finder.setHistogram(colorhist);
    cv::Mat detect = cv::imread("/home/dzh/QtOpenCV/image.png");
    cv::imshow("Detect", detect);
    cv::Mat hsv;
    cv::cvtColor(image, hsv, CV_BGR2HSV);
    vector<cv::Mat> v;
    cv::split(hsv, v);
    cv::Mat result;
    cv::threshold(v[1], v[1], minSat, 255, cv::THRESH_BINARY);
    result = finder.find(hsv, 0.0f, 180.0f, channels, 1);
    cv::bitwise_and(result, v[1], result);
    cv::Rect rect(110, 260, 35, 40);
    cv::rectangle(image, rect, cv::Scalar(255, 255, 255));
    cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER, 10, 0.01);
    cv::meanShift(result, rect, criteria);
//    cv::imshow("origin", colorhist);
    cv::imshow("output", result);
    cv::waitKey(0);
}

Representaciones de conversión de espacio de color:

inserte la descripción de la imagen aquí

Cuarto, use el histograma para contar píxeles

Una imagen se compone de píxeles con diferentes valores de color. La distribución de valores de píxeles en una imagen es una característica importante de esta imagen. Un histograma se puede calcular y utilizar para modificar la apariencia de una imagen. Para imágenes en escala de grises, el histograma es equivalente a una matriz de longitud 256, y cada elemento de la matriz representa el número de píxeles cuyo valor de escala de grises es el subíndice actual.

cv::Mat Histogram3D::getHistogramImage(cv::Mat &image) {
    
    
    // 先求取直方图(256x256x256)
    cv::MatND hist = getHistogram(image);
    // 设置最大值和最小值
    double maxVal = INT_MIN;
    double minVal = INT_MAX;
    // 创建显示图像256x256x3
    cv::Mat histImg(histSize[0], histSize[0], CV_8UC3, cv::Scalar(255, 255, 255));
    int hpt = static_cast<int>(0.9 * histSize[0]);
    // 3D->2D,可以减少一个维度
    vector<vector<float>> vec(3, vector<float>(256));
    // b通道
    for (int i = 0; i < 256; i++) {
    
    
        // g通道
        for (int j = 0; j < 256; j++) {
    
    
            // r通道
            for (int k = 0; k < 256; k++) {
    
    
                vec[0][i] += hist.at<float>(i, j, k);
                vec[1][j] += hist.at<float>(i, j, k);
                vec[2][k] += hist.at<float>(i, j, k);
            }
        }
    }
    // 先遍历每一行
    for (int i = 0; i < vec.size(); i++) {
    
    
        // 对于每一行直方图取最大值和最小值
        cv::minMaxLoc(vec[i], &minVal, &maxVal, 0, 0);
        cout << "maxVal:" << maxVal <<",minVal:" << minVal << endl;
        // 再遍历每一列
        for (int j = 0; j < vec[i].size(); j++) {
    
    
            float val = vec[i][j];
            int intensity = static_cast<int>(val * hpt / maxVal);
            cv::Scalar color;
            color[i] = 255;
            cv::line(histImg, cv::Point(j, histSize[i]), cv::Point(j, histSize[i] - intensity), color);
        }
    }
    return histImg;
}

Incluso la imagen de 640x480 más utilizada tiene 300 000 píxeles. Piense en 1080P y 4K cuando vea videos en horas normales, es decir, más de 30 cuadros por segundo, y cada cuadro tiene varios millones de píxeles.

inserte la descripción de la imagen aquí

5. Transformación de imágenes basada en operaciones morfológicas

La teoría del filtrado morfológico se propuso en la década de 1990 y se utiliza para analizar y procesar gráficos discretos. Define una serie de operaciones que aplican elementos de forma predefinidos para transformar una imagen. La forma en que un elemento de forma se cruza con los vecinos de un píxel determina el resultado de la operación. La erosión y la dilatación son las operaciones morfológicas más básicas. Dado que el filtrado morfológico generalmente se usa en imágenes binarias, los píxeles blancos se usan para representar objetos en primer plano y los píxeles negros se usan para representar el fondo. Las operaciones de apertura y cierre son las más básicas. Aquí demostramos el uso del filtrado morfológico para detectar bordes y esquinas de imágenes.

cv::Mat MorphoFeatures::getEdges(cv::Mat &image) {
    
    
    // 得到梯度图
    cv::Mat result;
    cv::morphologyEx(image, result, cv::MORPH_GRADIENT, cv::Mat());
    // 阈值化得到二值图像
    applyThreshold(result);
    return result;
}

void MorphoFeatures::setThreshold(int value) {
    
    
    threshold = value;
}

cv::Mat MorphoFeatures::getCorners(cv::Mat &image) {
    
    
    cv::Mat result;
    cv::dilate(image, result, cross);
    cv::erode(result, result, diamond);

    cv::Mat result2;
    cv::dilate(image, result2, x);
    cv::erode(result2, result, square);

    cv::absdiff(result2, result, result);
    applyThreshold(result);
    return result;
}

Las líneas rectas se pueden detectar fácilmente usando funciones integradas, y las esquinas deben definir 4 elementos estructurales: cuadrado, diamante, cruz y X.
inserte la descripción de la imagen aquí

Las imágenes se pueden segmentar mediante el algoritmo de cuenca hidrográfica y los objetos de primer plano también se pueden extraer mediante el algoritmo GrabCut.

6. Filtrado de imágenes

El filtrado es una operación básica en el procesamiento de señales y procesamiento de imágenes, cuyo objetivo es extraer selectivamente la parte de la imagen que se considera que transmite información importante en una aplicación específica. El filtrado elimina el ruido de una imagen, extrae características visuales de interés y permite volver a muestrear la imagen. El elemento en el centro de la matriz corresponde al píxel que el filtro está procesando actualmente. Tales matrices se denominan núcleos o máscaras. Los más utilizados son: filtro de media, filtro de mediana, filtro de Sobel y transformada de imagen de Laplace.

cv::Mat contoursInv;
cv::threshold(contours, contoursInv, 128, 255, cv::THRESH_BINARY_INV);
cv::imshow("Inv", contoursInv);
cv::Mat result1, result2;
cv::Sobel(image, result1, CV_8U, 1, 0, 3, 0.4, 128);
cv::Sobel(image, result2, CV_8U, 0, 1, 3, 0.4, 128);
cv::imshow("result1", result1);
cv::imshow("result2", result2);
cv::Mat sobelX, sobelY;
cv::Sobel(image, sobelX, CV_8U, 1, 0);
cv::Sobel(image, sobelY, CV_8U, 0, 1);
cv::Mat sobel;
sobel = sobelX + sobelY;
cv::imshow("Sobel", sobel);

La siguiente es la imagen original desde la parte superior izquierda, seguida de los resultados del filtrado medio, el filtrado mediano y el filtrado sobel. El filtrado medio generalmente desenfoca la imagen, y el filtrado mediano es muy efectivo para eliminar puntos de ruido. El operador sobel es ampliamente utilizado para detección de bordes o contornos.

inserte la descripción de la imagen aquí

7. Detectar y combinar puntos característicos

El concepto de puntos de interés (también llamados puntos clave o puntos característicos) en la visión por computadora se usa ampliamente para resolver problemas como el reconocimiento de objetos, la coincidencia de imágenes, el seguimiento visual y la reconstrucción 3D. cv::cornerHarris detecta las esquinas de Harris. Por supuesto, la detección rápida de esquinas es más rápida. El concepto de invariancia de escala significa que cada punto característico detectado va acompañado de un factor de tamaño correspondiente, entre los que se encuentra un punto característico muy popular: el punto característico SURF, que también es una variante eficiente del algoritmo SIFT.

En la coincidencia de características, los descriptores de características suelen ser vectores N-dimensionales, ideales para la iluminación y una pequeña transformación de la perspectiva. La detección de puntos característicos se puede resumir como: extraer puntos clave y calcular descriptores.

// 计算Harris角点
void HarrisDetector::detect(cv::Mat &image) {
    
    
    cv::cornerHarris(image, cornerStrength, neighbourhood, aperture, k);
    double minStrength;
    cv::minMaxLoc(cornerStrength, &minStrength, &maxStregth);
    cv::Mat dilated;
    cv::dilate(cornerStrength, dilated, cv::Mat());
    cv::compare(cornerStrength, dilated, localMax, cv::CMP_EQ);
}

// 由Harris值获取角点图
cv::Mat HarrisDetector::getCornerMap(double qualityLevel) {
    
    
    cv::Mat cornerMap;
    threshold = qualityLevel * maxStregth;
    cv::threshold(cornerStrength, cornerTh, threshold, 255, cv::THRESH_BINARY);
    cornerTh.convertTo(cornerMap, CV_8U);
    cv::bitwise_and(cornerMap, localMax, cornerMap);
    return cornerMap;
}

Por supuesto, las funciones de la biblioteca de detección de puntos de características anteriores no están en OpenCV, y todas están organizadas en la biblioteca de extensión por razones de patente. Para conocer el método de instalación, consulte mi tutorial: Ubuntu instala la biblioteca de extensión opencv_contrib, pisando el pozo + prueba

inserte la descripción de la imagen aquí

Por supuesto, la visión artificial es un tema muy amplio. Este artículo tiene un espacio limitado y solo puede explicar uno o dos. Los estudiantes interesados ​​pueden leer libros relacionados. Ahora, las tareas principales de CV son el reconocimiento de objetivos, la detección de objetivos y el seguimiento de objetivos. La estructura de la red también ha cambiado de la CNN tradicional a Transformer. ¡El rápido desarrollo de la inteligencia artificial es inseparable de CV, y también es inseparable de sus contribuciones de código abierto!

Supongo que te gusta

Origin blog.csdn.net/qq_42257666/article/details/126650323
Recomendado
Clasificación