首页 > 技术文章 > 图像修复-P-Laplace修复模型

jgg54335 2021-03-20 22:39 原文

原理:

 

 

  C++代码(灰度图像):

#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <time.h>

using namespace cv;
using namespace std;

enum { PIXEL_WHITE = 1 };
typedef struct coord
{
	int i;
	int j;
	int color;
}Coord;

std::vector<Coord> create_mask(cv::Mat& mask);

void P_Laplace_GRAY(
	cv::Mat& input_array, std::vector<Coord>& mask_array, cv::Mat& output_array,
	int* total_iters, int total_stages, float* lambdas, float* as);

int main(int argc, char* argv[])
{
	cv::Mat output_array;

	cv::namedWindow("1", cv::WINDOW_AUTOSIZE);
	cv::namedWindow("2", cv::WINDOW_AUTOSIZE);
	cv::namedWindow("3", cv::WINDOW_AUTOSIZE);

	cv::Mat image_array = cv::imread("CDD.png");
	image_array.convertTo(image_array, CV_32FC1);
	cv::cvtColor(image_array, image_array, cv::COLOR_BGR2GRAY);
	cv::normalize(image_array, image_array, 0, 1, cv::NORM_MINMAX, CV_32FC1);
	cv::imshow("1", image_array);

	cv::Mat mask_array = cv::imread("1.png");
	std::vector<Coord> mask_data = create_mask(mask_array);

	/*
		P_Laplace_GRAY PDE Inpainting.
	*/
	int total_iters[] = { 500 };
	int total_stages = 2;
	float lambdas[] = { 0.2 };
	float as[] = { 0.1 };
	double t = getTickCount();//当前滴答数
	P_Laplace_GRAY(image_array, mask_data, output_array, total_iters, total_stages, lambdas, as);

	t = ((double)getTickCount() - t) / getTickFrequency();
	printf("算法用时:%f秒\n", t);

	cv::normalize(output_array, output_array, 0, 255.0, cv::NORM_MINMAX, CV_8UC1);
	output_array.convertTo(output_array, CV_8UC1);

	cv::imshow("2", mask_array);
	cv::imshow("3", output_array);
	cv::waitKey(0);
}

void P_Laplace_GRAY(
	cv::Mat& input_array, std::vector<Coord>& mask_array, cv::Mat& output_array,
	int* total_iters, int total_stages, float* lambdas, float* as)
{
	typedef unsigned char logical_type;

	//初始化输出图像
	input_array.copyTo(output_array);
	//掩模图像的大小
	int size_mask = mask_array.size();
	//在每个stage计算P-Laplace
	for (int stage = 0; stage < total_stages; stage++)
	{
		int total_iter = total_iters[stage];
		float lambda = lambdas[stage];
		float a = as[stage];

		float UO, UN, UW, US, UE, UNE, UNW, USW, USE;
		float Un, Ue, Uw, Us;
		float Wn, We, Ww, Ws;
		float Hon, Hoe, How, Hos;
		float Hoo;

		//算法运行
		for (int iter = 0; iter < total_iter; iter++)
		{
			for (int cont = 0; cont < size_mask; cont++)
			{
				Coord coord = mask_array.at(cont);
				int row = coord.i;
				int col = coord.j;

				UO = input_array.at<float>(row, col);
				UW = input_array.at<float>(row - 1, col);
				UE = input_array.at<float>(row + 1, col);
				UN = input_array.at<float>(row, col + 1);
				US = input_array.at<float>(row, col - 1);

				UNW = input_array.at<float>(row - 1, col + 1);
				USW = input_array.at<float>(row - 1, col - 1);
				UNE = input_array.at<float>(row + 1, col + 1);
				USE = input_array.at<float>(row + 1, col - 1);

				Un = sqrt((UO - UN) * (UO - UN) + ((UNW - UNE) / 2.0) * ((UNW - UNE) / 2.0));
				Ue = sqrt((UO - UE) * (UO - UE) + ((UNE - USE) / 2.0) * ((UNE - USE) / 2.0));
				Uw = sqrt((UO - UW) * (UO - UW) + ((UNW - USW) / 2.0) * ((UNW - USW) / 2.0));
				Us = sqrt((UO - US) * (UO - US) + ((USW - USE) / 2.0) * ((USW - USE) / 2.0));

				Wn = 1.0 / sqrt(sqrt(Un * Un + a * a));
				We = 1.0 / sqrt(sqrt(Ue * Ue + a * a));
				Ww = 1.0 / sqrt(sqrt(Uw * Uw + a * a));
				Ws = 1.0 / sqrt(sqrt(Us * Us + a * a));

				Hon = Wn / (Wn + We + Ww + Ws + lambda);
				Hoe = We / (Wn + We + Ww + Ws + lambda);
				How = Ww / (Wn + We + Ww + Ws + lambda);
				Hos = Ws / (Wn + We + Ww + Ws + lambda);

				Hoo = lambda / (Wn + We + Ww + Ws + lambda);
				input_array.at<float>(row, col) = (Hon * UN + Hoe * UE + How * UW + Hos * US + Hoo * UO);
				output_array.at<float>(row, col) = input_array.at<float>(row, col);
			}
			printf("%d\n", iter);
		}
	}
}


/*
	Save the inpainting domain to dinamic vector
*/
std::vector<Coord> create_mask(cv::Mat& mask)
{
	std::vector<Coord> mask_data;
	for (int i = 1; i < mask.rows - 1; i++)
	{
		for (int j = 1; j < mask.cols - 1; j++)
		{
			if (mask.at<cv::Vec3b>(i, j)[0] != 0)
			{ //BLUE GREEN RED --> white (255,255,255) 
				Coord xy;
				xy.i = i;
				xy.j = j;
				xy.color = PIXEL_WHITE;
				mask_data.push_back(xy);
			}
		}
	}
	return mask_data;
}

C++代码(RGB图像):

#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <time.h>

using namespace cv;
using namespace std;

enum { PIXEL_WHITE = 1 };
typedef struct coord
{
	int i;
	int j;
	int color;
}Coord;

std::vector<Coord> create_mask(cv::Mat& mask);

void P_Laplace_RGB(
	cv::Mat& input_array, std::vector<Coord>& mask_array, cv::Mat& output_array,
	int* total_iters, int total_stages, float* lambdas, float* as);

int main(int argc, char* argv[])
{
	cv::Mat output_array;

	cv::namedWindow("1", cv::WINDOW_AUTOSIZE);
	cv::namedWindow("2", cv::WINDOW_AUTOSIZE);
	cv::namedWindow("3", cv::WINDOW_AUTOSIZE);

	/* Load and normalize the image */
	cv::Mat image_array = cv::imread("2.png");
	cv::imshow("1", image_array);
	image_array.convertTo(image_array, CV_32FC3);
	cv::normalize(image_array, image_array, 0, 1, cv::NORM_MINMAX, CV_32FC3);

	/* Load the mask and fill the vector*/
	cv::Mat mask_array = cv::imread("1.png");
	std::vector<Coord> mask_data = create_mask(mask_array);

	/*
		TV RGB PDE Inpainting.
	*/
	int total_iters[] = { 500 };
	int total_stages = 2;
	float lambdas[] = { 0.2 };
	float as[] = { 0.5 };
	double t = getTickCount();//当前滴答数
	P_Laplace_RGB(image_array, mask_data, output_array, total_iters, total_stages, lambdas, as);
	t = ((double)getTickCount() - t) / getTickFrequency();
	printf("算法用时:%f秒\n", t);
	/* Display the output */
	cv::normalize(output_array, output_array, 0, 255.0, cv::NORM_MINMAX, CV_8UC3);
	output_array.convertTo(output_array, CV_8UC3);
	imwrite("P.png", output_array);
	cv::imshow("2", mask_array);
	cv::imshow("3", output_array);
	cv::waitKey(0);
}

void P_Laplace_RGB(
	cv::Mat& input_array, std::vector<Coord>& mask_array, cv::Mat& output_array,
	int* total_iters, int total_stages, float* lambdas, float* as)
{
	typedef unsigned char logical_type;

	//初始化输出图像
	input_array.copyTo(output_array);
	//掩模图像的大小
	int size_mask = mask_array.size();
	//在每个stage计算P-Laplace
	for (int stage = 0; stage < total_stages; stage++)
	{
		int total_iter = total_iters[stage];
		float lambda = lambdas[stage];
		float a = as[stage];

		float UO1, UO2, UO3;
		float UN1, UN2, UN3;
		float UW1, UW2, UW3;
		float US1, US2, US3;
		float UE1, UE2, UE3;

		float UNE1, UNE2, UNE3;
		float UNW1, UNW2, UNW3;
		float USW1, USW2, USW3;
		float USE1, USE2, USE3;

		float Un1, Un2, Un3;
		float Ue1, Ue2, Ue3;
		float Uw1, Uw2, Uw3;
		float Us1, Us2, Us3;

		float Wn1, Wn2, Wn3;
		float We1, We2, We3;
		float Ww1, Ww2, Ww3;
		float Ws1, Ws2, Ws3;

		float Hon1, Hon2, Hon3;
		float Hoe1, Hoe2, Hoe3;
		float How1, How2, How3;
		float Hos1, Hos2, Hos3;

		float Hoo1, Hoo2, Hoo3;

		//算法运行
		for (int iter = 0; iter < total_iter; iter++)
		{
			for (int cont = 0; cont < size_mask; cont++)
			{
				Coord coord = mask_array.at(cont);
				int row = coord.i;
				int col = coord.j;

				UO1 = input_array.at<cv::Vec3f>(row, col)[0];
				UO2 = input_array.at<cv::Vec3f>(row, col)[1];
				UO3 = input_array.at<cv::Vec3f>(row, col)[2];

				UW1 = input_array.at<cv::Vec3f>(row - 1, col)[0];
				UW2 = input_array.at<cv::Vec3f>(row - 1, col)[1];
				UW3 = input_array.at<cv::Vec3f>(row - 1, col)[2];

				UE1 = input_array.at<cv::Vec3f>(row + 1, col)[0];
				UE2 = input_array.at<cv::Vec3f>(row + 1, col)[1];
				UE3 = input_array.at<cv::Vec3f>(row + 1, col)[2];

				UN1 = input_array.at<cv::Vec3f>(row, col + 1)[0];
				UN2 = input_array.at<cv::Vec3f>(row, col + 1)[1];
				UN3 = input_array.at<cv::Vec3f>(row, col + 1)[2];

				US1 = input_array.at<cv::Vec3f>(row, col - 1)[0];
				US2 = input_array.at<cv::Vec3f>(row, col - 1)[1];
				US3 = input_array.at<cv::Vec3f>(row, col - 1)[2];

				UNW1 = input_array.at<cv::Vec3f>(row - 1, col + 1)[0];
				UNW2 = input_array.at<cv::Vec3f>(row - 1, col + 1)[1];
				UNW3 = input_array.at<cv::Vec3f>(row - 1, col + 1)[2];

				USW1 = input_array.at<cv::Vec3f>(row - 1, col - 1)[0];
				USW2 = input_array.at<cv::Vec3f>(row - 1, col - 1)[1];
				USW3 = input_array.at<cv::Vec3f>(row - 1, col - 1)[2];

				UNE1 = input_array.at<cv::Vec3f>(row + 1, col + 1)[0];
				UNE2 = input_array.at<cv::Vec3f>(row + 1, col + 1)[1];
				UNE3 = input_array.at<cv::Vec3f>(row + 1, col + 1)[2];

				USE1 = input_array.at<cv::Vec3f>(row + 1, col - 1)[0];
				USE2 = input_array.at<cv::Vec3f>(row + 1, col - 1)[1];
				USE3 = input_array.at<cv::Vec3f>(row + 1, col - 1)[2];

				Un1 = sqrt((UO1 - UN1) * (UO1 - UN1) + ((UNW1 - UNE1) / 2.0) * ((UNW1 - UNE1) / 2.0));
				Ue1 = sqrt((UO1 - UE1) * (UO1 - UE1) + ((UNE1 - USE1) / 2.0) * ((UNE1 - USE1) / 2.0));
				Uw1 = sqrt((UO1 - UW1) * (UO1 - UW1) + ((UNW1 - USW1) / 2.0) * ((UNW1 - USW1) / 2.0));
				Us1 = sqrt((UO1 - US1) * (UO1 - US1) + ((USW1 - USE1) / 2.0) * ((USW1 - USE1) / 2.0));

				Un2 = sqrt((UO2 - UN2) * (UO2 - UN2) + ((UNW2 - UNE2) / 2.0) * ((UNW2 - UNE2) / 2.0));
				Ue2 = sqrt((UO2 - UE2) * (UO2 - UE2) + ((UNE2 - USE2) / 2.0) * ((UNE2 - USE2) / 2.0));
				Uw2 = sqrt((UO2 - UW2) * (UO2 - UW2) + ((UNW2 - USW2) / 2.0) * ((UNW2 - USW2) / 2.0));
				Us2 = sqrt((UO2 - US2) * (UO2 - US2) + ((USW2 - USE2) / 2.0) * ((USW2 - USE2) / 2.0));

				Un3 = sqrt((UO3 - UN3) * (UO3 - UN3) + ((UNW3 - UNE3) / 2.0) * ((UNW3 - UNE3) / 2.0));
				Ue3 = sqrt((UO3 - UE3) * (UO3 - UE3) + ((UNE3 - USE3) / 2.0) * ((UNE3 - USE3) / 2.0));
				Uw3 = sqrt((UO3 - UW3) * (UO3 - UW3) + ((UNW3 - USW3) / 2.0) * ((UNW3 - USW3) / 2.0));
				Us3 = sqrt((UO3 - US3) * (UO3 - US3) + ((USW3 - USE3) / 2.0) * ((USW3 - USE3) / 2.0));

				Wn1 = 1.0 / sqrt(sqrt(Un1 * Un1 + a * a));
				We1 = 1.0 / sqrt(sqrt(Ue1 * Ue1 + a * a));
				Ww1 = 1.0 / sqrt(sqrt(Uw1 * Uw1 + a * a));
				Ws1 = 1.0 / sqrt(sqrt(Us1 * Us1 + a * a));

				Wn2 = 1.0 / sqrt(sqrt(Un2 * Un2 + a * a));
				We2 = 1.0 / sqrt(sqrt(Ue2 * Ue2 + a * a));
				Ww2 = 1.0 / sqrt(sqrt(Uw2 * Uw2 + a * a));
				Ws2 = 1.0 / sqrt(sqrt(Us2 * Us2 + a * a));

				Wn3 = 1.0 / sqrt(sqrt(Un3 * Un3 + a * a));
				We3 = 1.0 / sqrt(sqrt(Ue3 * Ue3 + a * a));
				Ww3 = 1.0 / sqrt(sqrt(Uw3 * Uw3 + a * a));
				Ws3 = 1.0 / sqrt(sqrt(Us3 * Us3 + a * a));

				Hon1 = Wn1 / (Wn1 + We1 + Ww1 + Ws1 + lambda);
				Hoe1 = We1 / (Wn1 + We1 + Ww1 + Ws1 + lambda);
				How1 = Ww1 / (Wn1 + We1 + Ww1 + Ws1 + lambda);
				Hos1 = Ws1 / (Wn1 + We1 + Ww1 + Ws1 + lambda);

				Hon2 = Wn2 / (Wn2 + We2 + Ww2 + Ws2 + lambda);
				Hoe2 = We2 / (Wn2 + We2 + Ww2 + Ws2 + lambda);
				How2 = Ww2 / (Wn2 + We2 + Ww2 + Ws2 + lambda);
				Hos2 = Ws2 / (Wn2 + We2 + Ww2 + Ws2 + lambda);

				Hon3 = Wn3 / (Wn3 + We3 + Ww3 + Ws3 + lambda);
				Hoe3 = We3 / (Wn3 + We3 + Ww3 + Ws3 + lambda);
				How3 = Ww3 / (Wn3 + We3 + Ww3 + Ws3 + lambda);
				Hos3 = Ws3 / (Wn3 + We3 + Ww3 + Ws3 + lambda);

				Hoo1 = lambda / (Wn1 + We1 + Ww1 + Ws1 + lambda);
				Hoo2 = lambda / (Wn2 + We2 + Ww2 + Ws2 + lambda);
				Hoo3 = lambda / (Wn3 + We3 + Ww3 + Ws3 + lambda);

				input_array.at<cv::Vec3f>(row, col)[0] = (Hon1 * UN1 + Hoe1 * UE1 + How1 * UW1 + Hos1 * US1 + Hoo1 * UO1);
				input_array.at<cv::Vec3f>(row, col)[1] = (Hon2 * UN2 + Hoe2 * UE2 + How2 * UW2 + Hos2 * US2 + Hoo2 * UO2);
				input_array.at<cv::Vec3f>(row, col)[2] = (Hon3 * UN3 + Hoe3 * UE3 + How3 * UW3 + Hos3 * US3 + Hoo3 * UO3);

				output_array.at<cv::Vec3f>(row, col)[0] = input_array.at<cv::Vec3f>(row, col)[0];
				output_array.at<cv::Vec3f>(row, col)[1] = input_array.at<cv::Vec3f>(row, col)[1];
				output_array.at<cv::Vec3f>(row, col)[2] = input_array.at<cv::Vec3f>(row, col)[2];
			}
			printf("%d\n", iter);
		}
	}
}

/*
	Save the inpainting domain to dinamic vector
*/
std::vector<Coord> create_mask(cv::Mat& mask)
{
	std::vector<Coord> mask_data;
	for (int i = 1; i < mask.rows - 1; i++)
	{
		for (int j = 1; j < mask.cols - 1; j++)
		{
			if (mask.at<cv::Vec3b>(i, j)[0] != 0)
			{ //BLUE GREEN RED --> white (255,255,255) 
				Coord xy;
				xy.i = i;
				xy.j = j;
				xy.color = PIXEL_WHITE;
				mask_data.push_back(xy);
			}
		}
	}
	return mask_data;
}

测试图像:

 

 

推荐阅读