Registre algunas cosas sobre la optimización de la eficiencia operativa en los algoritmos de procesamiento de imágenes 20221016

Directorio de artículos de la serie de procesamiento de imágenes

prefacio

Registro de algunos procesos de optimización de la eficiencia en el procesamiento de imágenes
Algunos enlaces de referencia:
https://blog.csdn.net/libaineu2004/article/details/104129127
https://blog.csdn.net/qq_27278957/article/details/84646948

1. Comparación de métodos de píxeles de imágenes transversales

Tome atravesar todos los píxeles para invertir la imagen como ejemplo

#include "ImageProcess.h"

void PrintCostTime(double& t1, double& t2)
{
    
    
	double t = ((t2 - t1) / getTickFrequency()) * 1000;
	cout << "time: " << t << endl;
}
void method_at(Mat& _src)
{
    
    
	Mat src = _src.clone();
	double t1 = getTickCount();
	int w = src.cols;
	int h = src.rows;
	int dim = src.channels();
	for (int row = 0; row < h; row++) 
	{
    
    
		for (int col = 0; col < w; col++) 
		{
    
    
			if (dim == 3) {
    
    
				Vec3b bgr = src.at<Vec3b>(row, col);
				bgr[0] = 255 - bgr[0];
				bgr[1] = 255 - bgr[1];
				bgr[2] = 255 - bgr[2];
				src.at<Vec3b>(row, col) = bgr;
			}
			else if (dim == 1) {
    
    
				float pixel = src.at<uchar>(row, col);
				src.at<uchar>(row, col) =saturate_cast<uchar>(255 - pixel);
			}
		}
	}
	double t2 = getTickCount();
	PrintCostTime(t1, t2);
	imshow("result", src);
	waitKey(0);
}

void method_Matptr(Mat& _src)
{
    
    
	Mat src = _src.clone();
	double t1 = getTickCount();
	int w = src.cols;
	int h = src.rows;
	int dim = src.channels();
	if (dim == 3) {
    
    
		for (int row = 0; row < h; row++)
		{
    
    
			//uchar* pixel = src.ptr<uchar>(row);
			Vec3b* pixel = src.ptr<cv::Vec3b>(row);
			for (int col = 0; col < w; col++)
			{
    
    
				//pixel[0] = 255 - pixel[0];
				//pixel[1] = 255 - pixel[1];
				//pixel[2] = 255 - pixel[2];
				//pixel += 3;
				//Vec3b bgr = pixel[col];
				pixel[col][0] = 255 - pixel[col][0];
				pixel[col][1] = 255 - pixel[col][1];
				pixel[col][2] = 255 - pixel[col][2];
			}
		}
	}
	else if (dim == 1) {
    
    
		for (int row = 0; row < h; row++)
		{
    
    
			uchar* pixel = src.ptr<uchar>(row);
			for (int col = 0; col < w; col++)
			{
    
    
				pixel[0] = 255 - pixel[0];
				pixel ++;
				//pixel[col] = 255 - pixel[col];
				//*pixel++ = 255 - *pixel;
			}
		}
	}
	double t2 = getTickCount();
	PrintCostTime(t1, t2);
	imshow("result", src);
	waitKey(0);
}

void method_Dataptr(Mat& _src)
{
    
    
	Mat src = _src.clone();
	double t1 = getTickCount();
	int w = src.cols;
	int h = src.rows;
	int dim = src.channels();
	if (dim == 3) {
    
    
		for (int row = 0; row < h; row++)
		{
    
    
			uchar* pixel = src.data + row*src.step;
			for (int col = 0; col < w; col++)
			{
    
    
				pixel[0] = 255 - pixel[0];
				pixel[1] = 255 - pixel[1];
				pixel[2] = 255 - pixel[2];
				pixel += 3;
			}
		}
	}
	else if (dim == 1) {
    
    
		for (int row = 0; row < h; row++)
		{
    
    
			uchar* pixel = src.data + row * src.step;
			for (int col = 0; col < w; col++)
			{
    
    
				pixel[0] = 255 - pixel[0];
				pixel++;
				//pixel[col] = 255 - pixel[col];
				//*pixel++ = 255 - *pixel;
			}
		}
	}
	double t2 = getTickCount();
	PrintCostTime(t1, t2);
	imshow("result", src);
	waitKey(0);
}

void method_iterator(Mat& _src)
{
    
    
	Mat src = _src.clone();
	double t1 = getTickCount();
	int w = src.cols;
	int h = src.rows;
	int dim = src.channels();
	if (dim == 3) {
    
    
		Mat_<Vec3b>::iterator it = src.begin<Vec3b>();
		Mat_<Vec3b>::iterator itend = src.end<Vec3b>();
		for (; it != itend; ++it)
		{
    
    
			(*it)[0] = 255 - (*it)[0];
			(*it)[1] = 255 - (*it)[1];
			(*it)[2] = 255 - (*it)[2];
		}
	}
	if (dim == 1) {
    
    
		Mat_<uchar>::iterator it = src.begin<uchar>();
		Mat_<uchar>::iterator itend = src.end<uchar>();
		for (; it != itend; ++it)
		{
    
    
			(*it) = 255 - (*it);
		}
	}
	double t2 = getTickCount();
	PrintCostTime(t1, t2);
	imshow("result", src);
	waitKey(0);
}

Como puede ver, el método que usa punteros es el más rápido.
inserte la descripción de la imagen aquí

2. Usa OpenMP para acelerar

inserte la descripción de la imagen aquí
Si es Windows Visual Studio, configure openmp en las propiedades, si es Linux, agregue la configuración a CMakeLists.txt:

find_package(OpenMP REQUIRED)
if (OPENMP_FOUND)
	message("OPENMP FOUND")
    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
    set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

Modifique el código y agregue #pragma omp paralelo para num_threads(4) al bucle for

#include "ImageProcess.h"

void PrintCostTime(double& t1, double& t2)
{
    
    
	double t = ((t2 - t1) / getTickFrequency()) * 1000;
	cout << "time: " << t << endl;
}
void method_at(Mat& _src)
{
    
    
	Mat src = _src.clone();
	double t1 = getTickCount();
	int w = src.cols;
	int h = src.rows;
	int dim = src.channels();
#pragma omp parallel for num_threads(4)  //指定4个线程
	for (int row = 0; row < h; row++) 
	{
    
    
		for (int col = 0; col < w; col++) 
		{
    
    
			if (dim == 3) {
    
    
				Vec3b bgr = src.at<Vec3b>(row, col);
				bgr[0] = 255 - bgr[0];
				bgr[1] = 255 - bgr[1];
				bgr[2] = 255 - bgr[2];
				src.at<Vec3b>(row, col) = bgr;
			}
			else if (dim == 1) {
    
    
				float pixel = src.at<uchar>(row, col);
				src.at<uchar>(row, col) =saturate_cast<uchar>(255 - pixel);
			}
		}
	}
	double t2 = getTickCount();
	cout << "method_at ";
	PrintCostTime(t1, t2);
	imshow("result", src);
	waitKey(0);
}

void method_Matptr(Mat& _src)
{
    
    
	Mat src = _src.clone();
	double t1 = getTickCount();
	int w = src.cols;
	int h = src.rows;
	int dim = src.channels();
	if (dim == 3) {
    
    
#pragma omp parallel for num_threads(4)  //指定4个线程
		for (int row = 0; row < h; row++)
		{
    
    
			//uchar* pixel = src.ptr<uchar>(row);
			Vec3b* pixel = src.ptr<cv::Vec3b>(row);
			for (int col = 0; col < w; col++)
			{
    
    
				//pixel[0] = 255 - pixel[0];
				//pixel[1] = 255 - pixel[1];
				//pixel[2] = 255 - pixel[2];
				//pixel += 3;
				//Vec3b bgr = pixel[col];
				pixel[col][0] = 255 - pixel[col][0];
				pixel[col][1] = 255 - pixel[col][1];
				pixel[col][2] = 255 - pixel[col][2];
			}
		}
	}
	else if (dim == 1) {
    
    
#pragma omp parallel for num_threads(4)  //指定4个线程
		for (int row = 0; row < h; row++)
		{
    
    
			uchar* pixel = src.ptr<uchar>(row);
			for (int col = 0; col < w; col++)
			{
    
    
				pixel[0] = 255 - pixel[0];
				pixel ++;
				//pixel[col] = 255 - pixel[col];
				//*pixel++ = 255 - *pixel;
			}
		}
	}
	double t2 = getTickCount();
	cout << "method_Matptr ";
	PrintCostTime(t1, t2);
	imshow("result", src);
	waitKey(0);
}

void method_Dataptr(Mat& _src)
{
    
    
	Mat src = _src.clone();
	double t1 = getTickCount();
	int w = src.cols;
	int h = src.rows;
	int dim = src.channels();
	if (dim == 3) {
    
    
#pragma omp parallel for num_threads(4)  //指定4个线程
		for (int row = 0; row < h; row++)
		{
    
    
			uchar* pixel = src.data + row*src.step;
			for (int col = 0; col < w; col++)
			{
    
    
				pixel[0] = 255 - pixel[0];
				pixel[1] = 255 - pixel[1];
				pixel[2] = 255 - pixel[2];
				pixel += 3;
			}
		}
	}
	else if (dim == 1) {
    
    
#pragma omp parallel for num_threads(4)  //指定4个线程
		for (int row = 0; row < h; row++)
		{
    
    
			uchar* pixel = src.data + row * src.step;
			for (int col = 0; col < w; col++)
			{
    
    
				pixel[0] = 255 - pixel[0];
				pixel++;
				//pixel[col] = 255 - pixel[col];
				//*pixel++ = 255 - *pixel;
			}
		}
	}
	double t2 = getTickCount();
	cout << "method_Dataptr ";
	PrintCostTime(t1, t2);
	imshow("result", src);
	waitKey(0);
}

Vuelva a probar la velocidad y podrá ver que la velocidad se ha vuelto un poco más rápida. Esto se debe a que el ciclo for consume mucho tiempo. Si lo cambia a su propio algoritmo, la velocidad aún se puede mejorar mucho. Después de la optimización en mi propio proyecto, es de 700 De más de ms a ahora 120 ms, el efecto de mejora es muy bueno.
inserte la descripción de la imagen aquí

Resumir

Registro simple del proceso de procesamiento de imágenes.

Supongo que te gusta

Origin blog.csdn.net/zengwubbb/article/details/127353054
Recomendado
Clasificación