Notas de Opencv-C++ (15): reasignación de píxeles y distorsión de imágenes

1. Introducción a la reasignación

La reasignación es el proceso de colocar píxeles en una determinada posición de una imagen en una posición específica de otra imagen. Es decir:
inserte la descripción de la imagen aquí
durante el proceso de reasignación, el tamaño de la imagen también puede cambiar al mismo tiempo. En este momento, la relación entre píxeles no es una correspondencia uno a uno, por lo que el cálculo de interpolación de los valores de píxeles puede estar involucrado en el proceso de reasignación.

Remap(
InputArray src,       输入图像(灰度图或真彩图均可)
OutputArray dst,       输出图像(要求大小和xmap,ymap相同,通道数目及数据类型和src相同)
InputArray map1,      x 映射表 CV_32FC1/CV_32FC2
InputArray map2,      y 映射表
int interpolation,       选择的插值方法,常见线性插值,可选择立方等
int borderMode,       BORDER_CONSTANT
const Scalar borderValue   color
)

Archivo de encabezado quick_opencv.h: declarar clases y funciones públicas

#pragma once
#include <opencv2\opencv.hpp>
using namespace cv;

class QuickDemo {
    
    
public:
	...
	void remap_Demo(Mat& image1);
	void MLS(Mat& src, std::vector<Point> p, std::vector<Point> q);
	void MLS(Mat& src, int* p, int* q, int rows, int cols);
};

La función principal llama a las funciones miembro públicas de la clase.

#include <opencv2\opencv.hpp>
#include <quick_opencv.h>
#include <iostream>
using namespace cv;


int main(int argc, char** argv) {
    
    
	Mat src = imread("D:\\Desktop\\pandas_small22.png");
	if (src.empty()) {
    
    
		printf("Could not load images...\n");
		return -1;
	}
	
	QuickDemo qk;
	qk.remap_Demo(src);

	vector<Point> p{
    
    
		Point(30, 147), Point(147, 147), Point(268, 147), Point(112, 148),
		Point(186, 148), Point(98, 316), Point(211, 316)
	};
	vector<Point> q{
    
     
		Point(28, 209), Point(126, 143), Point(282, 26), Point(71, 236), 
		Point(136, 240), Point(79, 313), Point(190, 310)
	};
	qk.MLS(src1, p, q);

	int p_array[7][2] = {
    
     {
    
    30, 147}, {
    
    147, 147}, {
    
    268, 147}, {
    
    112, 148}, {
    
    186, 148}, {
    
    98, 316}, {
    
    211, 316} };
	int q_array[7][2] = {
    
     {
    
    28, 209}, {
    
    126, 143}, {
    
    282, 26},  {
    
    71, 236},  {
    
    136, 240}, {
    
    79, 313}, {
    
    190, 310} };
	qk.MLS(src1, (int *)p_array, (int*)q_array, 7, 2);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

Archivo fuente quick_demo.cpp: implementación de clases y funciones públicas

void update_map(Mat& image, int index, Mat& x_map, Mat& y_map) {
    
    
	int height = image.rows;
	int width = image.cols;
	double h_41 = height * 0.25;
	double h_43 = height * 0.75;
	double w_41 = width * 0.25;
	double w_43 = width * 0.75;
	for (int h = 0; h < height; h++) {
    
    
		float* x_ptr = x_map.ptr<float>(h);
		float* y_ptr = y_map.ptr<float>(h);
		for (int w = 0; w < width; w++) {
    
    
			switch (index)
			{
    
    
			case 0:
				if (h > h_41 && h < h_43 && w>w_41 && w < w_43) {
    
    
					*x_ptr++ = 2 * (w - w_41 + 0.5);
					*y_ptr++ = 2 * (h - h_41 + 0.5);
				}
				else
				{
    
    
					*x_ptr++ = 0;
					*y_ptr++ = 0;
				}
				break;
			case 1:
				*x_ptr++ = width - w - 1;
				*y_ptr++ = h;
				break;
			case 2:
				*x_ptr++ = w;
				*y_ptr++ = height - h - 1;
				break;
			case 3:
				*x_ptr++ = width - w - 1;
				*y_ptr++ = height - h - 1;
				break;
			}
		}
	}

}
void QuickDemo::remap_Demo(Mat& image) {
    
    
	Mat dst, x_map, y_map;
	int index = 0;
	x_map.create(image.size(), CV_32FC1);
	y_map.create(image.size(), CV_32FC1);

	
	int c = 0;
	while (true)
	{
    
    
		c = waitKey(400);
		if ((char)c==27){
    
    
			break;
		}
		index = c % 4;
		update_map(image,index, x_map, y_map);
		remap(image, dst, x_map, y_map, INTER_LINEAR, BORDER_CONSTANT, Scalar(255, 0, 0));
		imshow("remap", dst);
	}
}

Las dos funciones anteriores, update_map, se utilizan para actualizar el método de mapeo específico de remap, y remap_Demo es la función de llamada.
inserte la descripción de la imagen aquí

2. Distorsión de la imagen

Algoritmo MLS distorsión de imagen Deformación de imagen utilizando papel de mínimos cuadrados en movimiento .
El método de mínimos cuadrados (MLS) deforma la implementación de la imagen en Python
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Point NewPoint(Point V, vector<Point> p, vector<Point> q){
    
    
	vector<float>W;
	Point p_star, q_star = Point(0, 0);
	for (int i = 0; i <= p.size() - 1; i++){
    
    
		float temp;
		if (p[i] == V){
    
    
			temp = INT_MAX;
		}else{
    
    
			temp = 1.0 / (((p[i].x - V.x) * (p[i].x - V.x)) + ((p[i].y - V.y) * (p[i].y - V.y)));
		}
		W.push_back(temp);
	}
	float px = 0, py = 0, qx = 0, qy = 0, W_sum = 0;
	for (int i = 0; i <= W.size() - 1; i++){
    
    
		px += W[i] * p[i].x;
		py += W[i] * p[i].y;

		qx += W[i] * q[i].x;
		qy += W[i] * q[i].y;
		W_sum += W[i];
	}

	p_star.x = px / W_sum;
	p_star.y = py / W_sum;

	q_star.x = qx / W_sum;
	q_star.y = qy / W_sum;

	vector<Point> p_hat, q_hat;

	for (int i = 0; i <= p.size() - 1; i++){
    
    
		p_hat.push_back(p[i] - p_star);
		q_hat.push_back(q[i] - q_star);
	}
	Mat pi_hat_t_ = Mat::zeros(2, 1, CV_32FC1);
	Mat_<float> pi_hat_t = pi_hat_t_;

	Mat pi_hat_ = Mat::zeros(1, 2, CV_32FC1);
	Mat_<float> pi_hat = pi_hat_;

	Mat M_1_ = Mat::zeros(2, 2, CV_32FC1);
	Mat_<float> M_1 = M_1_;


	for (int i = 0; i <= p_hat.size() - 1; i++){
    
    
		pi_hat_t.at<float>(0, 0) = p_hat[i].x;
		pi_hat_t.at<float>(1, 0) = p_hat[i].y;

		pi_hat.at<float>(0, 0) = p_hat[i].x;
		pi_hat.at<float>(0, 1) = p_hat[i].y;

		M_1 += pi_hat_t * W[i] * pi_hat;
	}
	Mat_<float> M_1_inv = M_1.inv();
	M_1 = M_1_inv;

	Mat pj_hat_t_ = Mat::zeros(2, 1, CV_32FC1);
	Mat_<float> pj_hat_t = pj_hat_t_;

	Mat qj_hat_ = Mat::zeros(1, 2, CV_32FC1);
	Mat_<float> qj_hat = qj_hat_;

	Mat M_2_ = Mat::zeros(2, 2, CV_32FC1);
	Mat_<float> M_2 = M_2_;

	for (int j = 0; j <= q.size() - 1; j++){
    
    
		pj_hat_t.at<float>(0, 0) = p_hat[j].x;
		pj_hat_t.at<float>(1, 0) = p_hat[j].y;
		qj_hat.at<float>(0, 0) = q_hat[j].x;
		qj_hat.at<float>(0, 1) = q_hat[j].y;
		M_2 += W[j] * pj_hat_t * qj_hat;
	}
	Mat_<float> M = M_1 * M_2;//ok
	//cout << "M = " << M << endl;

	Point x_p_star = V - p_star;

	Mat M_x_p_star_ = Mat::zeros(1, 2, CV_32FC1);
	Mat_<float> M_x_p_star = M_x_p_star_;

	M_x_p_star.at<float>(0, 0) = x_p_star.x;
	M_x_p_star.at<float>(0, 1) = x_p_star.y;

	Mat M_q_star_ = Mat::zeros(1, 2, CV_32FC1);
	Mat_<float> M_q_star = M_q_star_;

	M_q_star.at<float>(0, 0) = q_star.x;
	M_q_star.at<float>(0, 1) = q_star.y;

	Mat_<float> Lv = M_x_p_star * M + M_q_star;
	return Point(Lv.at<float>(0, 0), Lv.at<float>(0, 1));
}



void QuickDemo::MLS(Mat& src, std::vector<Point> p, std::vector<Point> q){
    
    
    double time0 = static_cast<double>(getTickCount());
	Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
	for (int i = 0; i < src.rows; i++){
    
    
		for (int j = 0; j < src.cols; j++){
    
    
			Point old = Point(j, i);
			Point new_point = NewPoint(old, p, q);
			//cout << "old = " << old << "\tnew  = " << new_point << endl;

			dst.at<Vec3b>(i, j) = src.at<Vec3b>(abs(new_point.y), abs(new_point.x));
		}
	}
    double time1 = static_cast<double>(getTickCount());
	cout << "Total cost time is " << ((time1 - time0) / getTickFrequency()) << "seconds" << endl;
	imshow("dst_msl", dst);
}

función sobrecargada

Point NewPoint(Point V, float* W, int* p, int* q , float* p_hat, float* q_hat, int rows, int cols) {
    
    
	Point p_star, q_star = Point(0, 0);
	float temp = 0;
	float px = 0, py = 0, qx = 0, qy = 0, W_sum = 0;
	for (int i = 0; i < rows; i++) {
    
    
		int p_0 = *(p + i * cols);
		int p_1 = *(p + i * cols + 1);
		if (!(p_0 == V.x && p_1 == V.y)) {
    
    
			temp = 1.0 / (((p_0 - V.x) * (p_0 - V.x)) + ((p_1 - V.y) * (p_1 - V.y)));
		}else {
    
    
			temp = INT_MAX;
		}
		W[i] = temp;
		px += temp * p_0;
		py += temp * p_1;

		qx += temp * (*(q + i * cols));
		qy += temp * (*(q + i * cols + 1));

		W_sum += temp;
	}

	p_star.x = px / W_sum;
	p_star.y = py / W_sum;

	q_star.x = qx / W_sum;
	q_star.y = qy / W_sum;


	for (int i = 0; i < rows; i++) {
    
    
		*(p_hat + i * cols) = *(p + i * cols) - p_star.x;
		*(p_hat + i * cols + 1) = *(p + i * cols + 1) - p_star.y;

		*(q_hat + i * cols) = *(q + i * cols) - p_star.x;
		*(q_hat + i * cols + 1) = *(q + i * cols + 1) - p_star.y;
	}

	// ====================================
	Mat pi_hat_t_ = Mat::zeros(2, 1, CV_32FC1);
	Mat_<float> pi_hat_t = pi_hat_t_;

	Mat pi_hat_ = Mat::zeros(1, 2, CV_32FC1);
	Mat_<float> pi_hat = pi_hat_;

	Mat M_1_ = Mat::zeros(2, 2, CV_32FC1);
	Mat_<float> M_1 = M_1_;

	// ====================================
	Mat pj_hat_t_ = Mat::zeros(2, 1, CV_32FC1);
	Mat_<float> pj_hat_t = pj_hat_t_;

	Mat qj_hat_ = Mat::zeros(1, 2, CV_32FC1);
	Mat_<float> qj_hat = qj_hat_;

	Mat M_2_ = Mat::zeros(2, 2, CV_32FC1);
	Mat_<float> M_2 = M_2_;
	// ====================================
	for (int i = 0; i < rows; i++) {
    
    
		float p_hat_x = *(p_hat + i * cols);
		float p_hat_y = *(p_hat + i * cols + 1);

		pi_hat_t.at<float>(0, 0) = p_hat_x;
		pi_hat_t.at<float>(1, 0) = p_hat_y;
		pi_hat.at<float>(0, 0) = p_hat_x;
		pi_hat.at<float>(0, 1) = p_hat_y;
		M_1 += pi_hat_t * W[i] * pi_hat;

		pj_hat_t.at<float>(0, 0) = p_hat_x;
		pj_hat_t.at<float>(1, 0) = p_hat_y;
		qj_hat.at<float>(0, 0) = *(q_hat + i * cols);
		qj_hat.at<float>(0, 1) = *(q_hat + i * cols + 1);
		M_2 += pj_hat_t * W[i] * qj_hat;
	}
	Mat_<float> M_1_inv = M_1.inv();
	M_1 = M_1_inv;

	Mat_<float> M = M_1 * M_2;

	//=====================================
	//
	// 	  如下为总公式计算
	//
	//======================================

	Point x_p_star = V - p_star;

	Mat M_x_p_star_ = Mat::zeros(1, 2, CV_32FC1);
	Mat_<float> M_x_p_star = M_x_p_star_;

	M_x_p_star.at<float>(0, 0) = x_p_star.x;
	M_x_p_star.at<float>(0, 1) = x_p_star.y;

	Mat M_q_star_ = Mat::zeros(1, 2, CV_32FC1);
	Mat_<float> M_q_star = M_q_star_;

	M_q_star.at<float>(0, 0) = q_star.x;
	M_q_star.at<float>(0, 1) = q_star.y;

	Mat_<float> Lv = M_x_p_star * M + M_q_star;
	return Point(Lv.at<float>(0, 0), Lv.at<float>(0, 1));

}


void QuickDemo::MLS(Mat& src, int* p, int* q, int rows, int cols) {
    
    
	double time0 = static_cast<double>(getTickCount());
	Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
	assert(7 == rows);               // 若断言失败请修改如下三个数组的长度为rows
	float W[7] = {
    
     0 };              // 权重长度为p数组长度:rows=7
	float p_hat[7][2] = {
    
     0 };       // p_hat长度为p数组长度:rows=7
	float q_hat[7][2] = {
    
     0 };       // q_hat长度为p数组长度:rows=7
	for (int i = 0; i < src.rows; i++) {
    
    
		for (int j = 0; j < src.cols; j++) {
    
    
			Point new_point = NewPoint(Point(j, i), W, p, q, (float*)p_hat, (float*)p_hat, rows, cols);
			//cout << "old = " << old << "\tnew  = " << new_point << endl;

			dst.at<Vec3b>(i, j) = src.at<Vec3b>(abs(new_point.y), abs(new_point.x));
			//cout << "src.at<uchar> = " << src.at<Vec3b>(new_point.y,new_point.x) << endl;
		}
	}
	double time1 = static_cast<double>(getTickCount());
	cout << "Total cost time is " << ((time1 - time0) / getTickFrequency()) << "seconds" << endl;
	imshow("dst_msl", dst);
}
————

inserte la descripción de la imagen aquí
Agradecimientos y lecturas adicionales:
Utilice registros de ejemplo para registrar el algoritmo MLS de estiramiento facial de cuatro procesamiento de imágenes Implementación de C ++
Exploración del algoritmo de deformación local OpenCV Agregar descripción del enlace
Distorsión de imagen basada en mínimos cuadrados en movimiento (MLS) Deformación rígida Implementación de Python
Utilice reasignación para lograr distorsión local de la imagen para lograr una mejora de la imagen.

Supongo que te gusta

Origin blog.csdn.net/jiyanghao19/article/details/132104535
Recomendado
Clasificación