图像修复-BSCB修复模型
原理:
C++代码(灰度图像):
//#define OPENCV_TRAITS_ENABLE_DEPRECATED #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); //BSCB模型 void BSCB_GRAY( cv::Mat& input_array, std::vector<Coord>& mask_array, cv::Mat& output_array, int* total_iters, int* total_inpaint_iters, int* total_anidiffuse_iters, int total_stages, float* delta_ts, float* sensitivities, int diffuse_coef); int main(int argc, char* argv[]) { cv::Mat output_array; /* Load and normalize the image */ cv::Mat image_array = cv::imread("lena.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); /* Load the mask and fill the vector*/ cv::Mat mask_array = cv::imread("lena_mask.png"); std::vector<Coord> mask_data = create_mask(mask_array); /* Create the windows */ cv::namedWindow("1", cv::WINDOW_AUTOSIZE); cv::namedWindow("2", cv::WINDOW_AUTOSIZE); cv::namedWindow("3", cv::WINDOW_AUTOSIZE); /* Bertalmio PDE Inpainting. */ int total_iters[] = { 200 }; int total_inpaint_iters[] = { 6 }; int total_anidiffuse_iters[] = { 6 }; int total_stages = 2; float delta_ts[] = { 0.02f }; float sensitivites[] = { 100 }; int diffuse_coef = 1; double t = getTickCount();//当前滴答数 BSCB_GRAY( image_array, mask_data, output_array, total_iters, total_inpaint_iters, total_anidiffuse_iters, total_stages, delta_ts, sensitivites, diffuse_coef); 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); /* Display the output */ cv::imshow("1", image_array); cv::imshow("2", mask_array); cv::imshow("3", output_array); cv::waitKey(0); } void BSCB_GRAY( cv::Mat& input_array, std::vector<Coord>& mask_array, cv::Mat& output_array, int* total_iters, int* total_inpaint_iters, int* total_anidiffuse_iters, int total_stages, float* delta_ts, float* sensitivities, int diffuse_coef) { typedef unsigned char logical_type; cv::Mat image_grad_row; cv::Mat image_grad_col; cv::Mat image_grad_norm; cv::Mat image_iso_row; cv::Mat image_iso_col; cv::Mat image_iso_norm; cv::Mat image_laplacian; cv::Mat image_laplacian_grad_row; cv::Mat image_laplacian_grad_col; cv::Mat diffuse_coefs; cv::Mat temp; //初始化输出图像 input_array.copyTo(output_array); //掩模图像的大小 int size_mask = mask_array.size(); //在每个stage计算BSCB for (int stage = 0; stage < total_stages; stage++) { int total_iter = total_iters[stage]; int total_inpaint_iter = total_inpaint_iters[stage]; int total_anidiffuse_iter = total_anidiffuse_iters[stage]; float sensitivity = sensitivities[stage]; float delta_t = delta_ts[stage]; //算法运行 for (int iter = 0; iter < total_iter; iter++) { //执行各向异性扩散 for (int iter_aniffuse = 0; iter_aniffuse < total_anidiffuse_iter; iter_aniffuse++) { cv::Sobel(output_array, image_grad_row, -1, 0, 1); cv::Sobel(output_array, image_grad_col, -1, 1, 0); cv::magnitude(image_grad_row, image_grad_col, image_grad_norm); if (diffuse_coef == 0) { cv::exp(-(image_grad_norm.mul(1 / sensitivity)), diffuse_coefs); } else { cv::pow(image_grad_norm.mul(1 / sensitivity), 2, temp); diffuse_coefs = 1 / (1 + temp); } cv::Laplacian(output_array, image_laplacian, -1); for (int cont = 0; cont < size_mask; cont++) { Coord coord = mask_array.at(cont); int row = coord.i; int col = coord.j; output_array.at<float>(row, col) += delta_t * (diffuse_coefs.at<float>(row, col) * image_laplacian.at<float>(row, col)); } } //算法运行 for (int total_inpaint_iters = 0; total_inpaint_iters < total_inpaint_iter; total_inpaint_iters++) { cv::Sobel(output_array, image_iso_row, -1, 1, 0); cv::Sobel(output_array, image_iso_col, -1, 0, 1); image_iso_row *= -1; cv::sqrt(image_iso_row.mul(image_iso_row) + image_iso_col.mul(image_iso_col), image_iso_norm); cv::Laplacian(output_array, image_laplacian, -1); cv::Sobel(image_laplacian, image_laplacian_grad_row, -1, 0, 1); cv::Sobel(image_laplacian, image_laplacian_grad_col, -1, 1, 0); for (int cont = 0; cont < size_mask; cont++) { Coord coord = mask_array.at(cont); int row = coord.i; int col = coord.j; if (image_iso_norm.at<float>(row, col) != 0) { output_array.at<float>(row, col) -= delta_t * ( image_iso_row.at<float>(row, col) * image_laplacian_grad_row.at<float>(row, col) + image_iso_col.at<float>(row, col) * image_laplacian_grad_col.at<float>(row, col)) / image_iso_norm.at<float>(row, col); output_array.at<float>(row, col) = (output_array.at<float>(row, col) > 1.0f ? 1 : output_array.at<float>(row, col)); output_array.at<float>(row, col) = (output_array.at<float>(row, col) < 0.0f ? 0 : output_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图像):
//#define OPENCV_TRAITS_ENABLE_DEPRECATED #include "opencv2/opencv.hpp"; #include <thread> #include <iostream> #include <stdlib.h> #include <math.h> #include<vector> #include <opencv2/highgui/highgui.hpp> #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <time.h> using namespace std; using namespace cv; enum { PIXEL_WHITE = 1 }; typedef struct coord { int i; int j; int color; }Coord; std::vector<Coord> create_mask(cv::Mat& mask); void BSCB_GRAY( cv::Mat& input_array, std::vector<Coord>& mask_array, cv::Mat& output_array, int* total_iters, int* total_inpaint_iters, int* total_anidiffuse_iters, int total_stages, float* delta_ts, float* sensitivities, int diffuse_coef); int main(int argc, char* argv[]) { cv::Mat output_array; cv::Mat res(output_array.rows, output_array.cols, CV_32FC3); //用来存储目的图片的矩阵 /* Create the windows */ 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("test.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); cv::Mat r(image_array.rows, image_array.cols, CV_32FC1); cv::Mat g(image_array.rows, image_array.cols, CV_32FC1); cv::Mat b(image_array.rows, image_array.cols, CV_32FC1); vector<Mat> out = { b,g,r }; split(image_array, out); /* Load the mask and fill the vector*/ cv::Mat mask_array = cv::imread("test_mask.png"); std::vector<Coord> mask_data = create_mask(mask_array); /* Bertalmio PDE Inpainting. */ int total_iters[] = { 500 }; int total_inpaint_iters[] = { 6 }; int total_anidiffuse_iters[] = { 6 }; int total_stages = 2; float delta_ts[] = { 0.02f }; float sensitivites[] = { 100 }; int diffuse_coef = 1; BSCB_GRAY( b, mask_data, b, total_iters, total_inpaint_iters, total_anidiffuse_iters, total_stages, delta_ts, sensitivites, diffuse_coef); BSCB_GRAY( g, mask_data, g, total_iters, total_inpaint_iters, total_anidiffuse_iters, total_stages, delta_ts, sensitivites, diffuse_coef); BSCB_GRAY( r, mask_data, r, total_iters, total_inpaint_iters, total_anidiffuse_iters, total_stages, delta_ts, sensitivites, diffuse_coef); merge(out, output_array); cv::normalize(output_array, output_array, 0, 255.0, cv::NORM_MINMAX, CV_8UC3); output_array.convertTo(output_array, CV_8UC3); imwrite("1.png", output_array); /* Display the output */ cv::imshow("2", mask_array); cv::imshow("3", output_array); cv::waitKey(0); } void BSCB_GRAY( cv::Mat& input_array, std::vector<Coord>& mask_array, cv::Mat& output_array, int* total_iters, int* total_inpaint_iters, int* total_anidiffuse_iters, int total_stages, float* delta_ts, float* sensitivities, int diffuse_coef) { typedef unsigned char logical_type; cv::Mat image_grad_row; cv::Mat image_grad_col; cv::Mat image_grad_norm; cv::Mat image_iso_row; cv::Mat image_iso_col; cv::Mat image_iso_norm; cv::Mat image_laplacian; cv::Mat image_laplacian_grad_row; cv::Mat image_laplacian_grad_col; cv::Mat diffuse_coefs; cv::Mat temp; //初始化输出图像 input_array.copyTo(output_array); //掩模图像的大小 int size_mask = mask_array.size(); //在每个stage计算BSCB for (int stage = 0; stage < total_stages; stage++) { int total_iter = total_iters[stage]; int total_inpaint_iter = total_inpaint_iters[stage]; int total_anidiffuse_iter = total_anidiffuse_iters[stage]; float sensitivity = sensitivities[stage]; float delta_t = delta_ts[stage]; //算法运行 for (int iter = 0; iter < total_iter; iter++) { //执行各向异性扩散 for (int iter_aniffuse = 0; iter_aniffuse < total_anidiffuse_iter; iter_aniffuse++) { cv::Sobel(output_array, image_grad_row, -1, 0, 1); cv::Sobel(output_array, image_grad_col, -1, 1, 0); cv::magnitude(image_grad_row, image_grad_col, image_grad_norm); if (diffuse_coef == 0) { cv::exp(-(image_grad_norm.mul(1 / sensitivity)), diffuse_coefs); } else { cv::pow(image_grad_norm.mul(1 / sensitivity), 2, temp); diffuse_coefs = 1 / (1 + temp); } cv::Laplacian(output_array, image_laplacian, -1); for (int cont = 0; cont < size_mask; cont++) { Coord coord = mask_array.at(cont); int row = coord.i; int col = coord.j; output_array.at<float>(row, col) += delta_t * (diffuse_coefs.at<float>(row, col) * image_laplacian.at<float>(row, col)); } } //算法运行 for (int total_inpaint_iters = 0; total_inpaint_iters < total_inpaint_iter; total_inpaint_iters++) { cv::Sobel(output_array, image_iso_row, -1, 1, 0); cv::Sobel(output_array, image_iso_col, -1, 0, 1); image_iso_row *= -1; cv::sqrt(image_iso_row.mul(image_iso_row) + image_iso_col.mul(image_iso_col), image_iso_norm); cv::Laplacian(output_array, image_laplacian, -1); cv::Sobel(image_laplacian, image_laplacian_grad_row, -1, 0, 1); cv::Sobel(image_laplacian, image_laplacian_grad_col, -1, 1, 0); for (int cont = 0; cont < size_mask; cont++) { Coord coord = mask_array.at(cont); int row = coord.i; int col = coord.j; if (image_iso_norm.at<float>(row, col) != 0) { output_array.at<float>(row, col) -= delta_t * ( image_iso_row.at<float>(row, col) * image_laplacian_grad_row.at<float>(row, col) + image_iso_col.at<float>(row, col) * image_laplacian_grad_col.at<float>(row, col)) / image_iso_norm.at<float>(row, col); output_array.at<float>(row, col) = (output_array.at<float>(row, col) > 1.0f ? 1 : output_array.at<float>(row, col)); output_array.at<float>(row, col) = (output_array.at<float>(row, col) < 0.0f ? 0 : output_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; }
测试图像:
转载请注明出处,欢迎讨论和交流!