OpenCV lector de códigos QR

A partir de la versión 4.0.0 de OpenCV se agregó la funcionalidad de poder detectar y decodificar códigos QR sin necesidad de librerías externas, sin embargo la misma no realizaba el trabajo de la mejor manera, en la reciente versión 4.1.2 se agregaron mejoras que probaremos en día de hoy, veremos como usar OpenCV para crear un detector y decodificador de códigos QR en tiempo real con unas pocas líneas de código C++.

QR OpenCV

La clase encargada de realizar la respectiva tarea es QRCodeDetector, usando sus métodos detect(...) podremos detectar un código QR en una imagen en colores o a escala de grises, con decode(...) decodificamos el código y obtenemos la información que contenga el mismo, para nuestro ejemplo una URL, también podremos usar detectAndDecode(...) para hacer ambas tareas en una sola llamada.

int main(int argc, char* argv[])
{
	// Init QR Detector
	QRCodeDetector qr = QRCodeDetector::QRCodeDetector();

	VideoCapture capture;
	if (capture.open(0)) {

		while (true) {

			Mat frame;
			capture >> frame;

			if (frame.empty()) continue;

			vector<Point> pts;
			if (qr.detect(frame, pts)) {

				string decoded = qr.decode(frame, pts);
				drawQRCodeContour(frame, pts, decoded);
			}

			imshow("QR", frame);

			if(waitKey(30) == 27) break;
		}

		capture.release();
	}
}

Lo primero es crear una instancia de la clase QRCodeDetector para luego iniciar el VideoCapture que nos permitirá leer imágenes desde nuestra webcam, esto ya se ha explicado en tutoriales anteriores, así que nos centramos directamente en el siguiente fragmento de código que es el que nos interesa en este momento:

vector<Point> pts;
if (qr.detect(frame, pts)) { 

	string decoded = qr.decode(frame, pts);
	if(!decoded.empty()) drawQRCodeContour(frame, pts, decoded);
}

Aquí usamos el método qr.detect(frame, pts) para detectar el QR presente en la entrada, para nuestro ejemplo el cv::Mat frame, debemos indicar un vector<cv::Point> en donde se almacenará los puntos que corresponden al las 4 esquinas del QR, este método retorna true en caso de éxito.

Lo que sigue es usar el método qr.decode(frame, pts) para obtener el texto contenido por el QR, le pasamos los datos obtenidos previamente, opcionalmente a este método se le puede pasar un tercer argumento que es un cv::Mat que contendrá una versión retificada del QR, es decir una imágen recortada y alineada.

También debes saber que es posible hacer ambas cosas en una sola llamada usando el método qr.detectAndDecode(...).

Sí hemos logrado detectar y decodificar correctamente la información podemos mostrarla, para ello usamos la siguiente función a la cuál le pasamos la imagen, los puntos y texto decodificado.

void drawQRCodeContour(Mat& color_image, vector<Point> pts, string url)
{
	if (!pts.empty())
	{
		for (int i = 0; i < 4; i++) {
			line(color_image, pts.at(i), pts.at((i + 1) % 4), Scalar(0, 255, 0), 1, LINE_AA);
		}

		RNG rng(1000);
		for (size_t i = 0; i < 4; i++)
		{
			Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
			circle(color_image, pts[i], 6.5, color, FILLED, LINE_AA);
		}

		putText(color_image, url, Point(10, 30), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 255), 1, LINE_AA);
	}
}

En el primer fragmento de código usamos line(...), para crear una línea que una cada uno de los puntos encontrados, en el segundo con circle(...) dibujamos un circulo en cada una de las esquinas y al final con putText(...) escribimos el texto decodificado.

En el repositorio de este projecto podrás encontrar el CMakeLists.txt que te facilitará la generación del proyecto.

cmake_minimum_required(VERSION 3.0)  
PROJECT(qr-opencv)

FIND_PACKAGE( OpenCV REQUIRED )
INCLUDE_DIRECTORIES( ${OpenCV_INCLUDE_DIRS} )

ADD_EXECUTABLE(${PROJECT_NAME} main.cpp)
TARGET_LINK_LIBRARIES (${PROJECT_NAME} ${OpenCV_LIBS})  

Código de proyecto en GitHub

Comentarios

Publicar un comentario

Temas relacionados

Entradas populares de este blog

tkinter Grid

tkinter Canvas

Histogramas OpenCV Python

Python Binance API