天天看点

【OpenCV】纹理迁移

【OpenCV】纹理迁移

+

【OpenCV】纹理迁移

||

【OpenCV】纹理迁移

程序:

pch.h

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace cv;
using namespace std;

Mat SearchForSimilarAreas(Mat currentPatch, Mat texturePic);
Mat Horizontal(Mat rock1_, Mat rock2_, int cutCols);
Mat Vertical(Mat rock1_, Mat rock2_, int cutRows);

           

TextureTransfer.cpp

#include "pch.h"

int main(void)
{
	string infileName, texturefileName, outfileName;
	int patchSize = 16;
	int overlappingSize = 8;

	infileName = "texture_transfer.bmp";
	texturefileName = "rice.jpg";
	outfileName = "debug.bmp";

	Mat pic = imread(infileName);
	Mat texturePic = imread(texturefileName);
	Mat rowsPatch, rowsTempPatch, transferPic, transferTempPic;

	int stride = patchSize - overlappingSize;
	int rowsPos = 0, colsPos = 0;

	for (int w = 0; w < pic.rows; w += stride) // makeup picture by vertical texture synthesis 
	{
		int rangeRow = patchSize;
		if (w + patchSize > pic.rows) // handle the bottom small row picture
		{
			rangeRow = pic.rows - w;
		}
		Mat colsPatch, colsTempPatch;
		for (int i = 0; i < pic.cols; i += stride)  // makeup picture by horizontal texture synthesis
		{
			int rangeCol = patchSize;
			Mat patch, similarPatch;

			if (i + patchSize > pic.cols) // handle rightmost small col picture
			{
				rangeCol = pic.cols - i;
			}
			patch.create(rangeRow, rangeCol, CV_8UC3);
			for (int j = 0; j < rangeRow; j++) // create the patch to be found in texture picture
			{
for (int k = 0; k < rangeCol; k++)
				{
					Vec3b RGB = pic.at<Vec3b>(w + j, i + k);
					patch.at<Vec3b>(j, k) = RGB;
				}
			}
			similarPatch = SearchForSimilarAreas(patch, texturePic).clone();			if (i == 0)
			{
				colsPatch = similarPatch.clone();
			}
			else {				if (rangeCol > overlappingSize)
					colsTempPatch = Horizontal(colsPatch, similarPatch, overlappingSize).clone();
				else {
					break;
				}
				colsPatch = colsTempPatch.clone();
			}
		}
		if (w == 0) // synthesis one line picture to the big picture
		{
			transferPic = colsPatch.clone();
		}
		else {
			if (rangeRow > overlappingSize)
				transferTempPic = Vertical(transferPic, colsPatch, overlappingSize).clone();
			else {
				break;
			}
			transferPic = transferTempPic.clone();
		}
	}
imshow("src_pic 1210", pic);
	imshow("tex_pic 1210", texturePic);
	imshow("tran_pic 1210", transferPic);

	imwrite(outfileName, transferPic);
	waitKey(0);
	return 0;
}

           

SearchForSimilarAreas.cpp

#include "pch.h"

typedef struct minimumDifferenceLocation
{
	int row_num = 0;
	int col_num = 0;
	int pixelDifference = 0;
}MinimumDifferenceLocation;

bool compare_minimumDifferenceLocationArray(MinimumDifferenceLocation const struct1, MinimumDifferenceLocation const struct2);

Mat SearchForSimilarAreas(Mat currentPatch, Mat texturePic)
{
	int patchCols = currentPatch.cols; // the cols number of the patch is currently being compared
	int patchRows = currentPatch.rows; // the rows number of the patch is currently being compared
	int textureCols = texturePic.cols; // the cols number of texture picture
	int textureRows = texturePic.rows; // the rows number of texture picture
	int rows_need_be_compared = textureRows - patchRows; // max rows number of pixel rows pointer can reach
	int cols_need_be_compared = textureCols - patchCols; // max cols number of pixel cols pointer can reach
	

	int **gray_scale_difference_sum;  // contains the result of gray scale difference for each possible reached pixel
	gray_scale_difference_sum = (int**)calloc(rows_need_be_compared, sizeof(int*)); // calloc memory space for gray_scale_difference array
	for (int i = 0; i < rows_need_be_compared; i++)
	{
		gray_scale_difference_sum[i] = (int*)calloc(cols_need_be_compared, sizeof(int));
	}
	for (int i = 0; i < rows_need_be_compared; i++) // initialize gray_scale_difference array
	{
		for (int j = 0; j < cols_need_be_compared; j++)
			gray_scale_difference_sum[i][j] = 0;
	}

	Mat grayCurrentPatch, grayTexturePic;
	cvtColor(currentPatch, grayCurrentPatch, CV_BGR2GRAY, 0);  // colored currently being compared patch is transferred to gray patch
	cvtColor(texturePic, grayTexturePic, CV_BGR2GRAY, 0);  // colored texture picture is transferred to gray picture


	
	int minPixelRowPositon = 0;
	int minPixelColPosition = 0;
	int minimumDifferenceSum = INT_MAX;
	int speedupValue = 3;
	MinimumDifferenceLocation* minimumDifferenceLocationArray = (MinimumDifferenceLocation*)calloc(cols_need_be_compared, sizeof(MinimumDifferenceLocation));
	for (int i = 0; i < rows_need_be_compared; i += speedupValue)
	{
		for (int j = 0; j < cols_need_be_compared; j ++)
		{
			for (int k = 0; k < patchRows; k += speedupValue)  // calculate the sum of the gray scale difference for each possible similar patch
			{
				for (int l = 0; l < patchCols; l += speedupValue)
				{
					gray_scale_difference_sum[i][j] += abs(grayCurrentPatch.at<uchar>(k, l) - grayTexturePic.at<uchar>(i + k, j + l)); // the gray scale difference
				}
			}
			minimumDifferenceLocationArray[j].row_num = i;
			minimumDifferenceLocationArray[j].col_num = j;
			minimumDifferenceLocationArray[j].pixelDifference = gray_scale_difference_sum[i][j];
		}

		sort(minimumDifferenceLocationArray, minimumDifferenceLocationArray + cols_need_be_compared, compare_minimumDifferenceLocationArray);
		if (minimumDifferenceLocationArray[0].pixelDifference < minimumDifferenceSum)
		{
			 minPixelRowPositon = minimumDifferenceLocationArray[0].row_num;
			 minPixelColPosition = minimumDifferenceLocationArray[0].col_num;
			 minimumDifferenceSum = minimumDifferenceLocationArray[0].pixelDifference;
		}
	}

	/*
	for (int i = 0; i < rows_need_be_compared; i++) // find the most similar patch in texture picture using Brute force
	{
		for (int j = 0; j < cols_need_be_compared; j++)
		{
			if (*min_element(gray_scale_difference_sum[i], gray_scale_difference_sum[i] + cols_need_be_compared) < minimumDifferenceSum)  // update currently the max similar patch coordinate
			{
				minimumDifferenceSum = *min_element(gray_scale_difference_sum[i], gray_scale_difference_sum[i] + cols_need_be_compared); // update minimum difference sum

				minPixelRowPositon = i;
				minPixelColPosition = distance(gray_scale_difference_sum[i], min_element(gray_scale_difference_sum[i], gray_scale_difference_sum[i] + cols_need_be_compared));
			}
		}
	}
	*/

	printf("rows at %d\n", minPixelRowPositon);
	printf("cols at %d\n", minPixelColPosition);

	Mat theSimilarPath;
	theSimilarPath.create(patchRows, patchCols, CV_8UC3);
	for (int i = 0; i < patchRows; i++) // create the most similar patch
	{
		for (int j = 0; j < patchCols; j++)
		{
			Vec3b RGB = texturePic.at<Vec3b>(minPixelRowPositon + i, minPixelColPosition + j);
			theSimilarPath.at<Vec3b>(i, j) = RGB;
		}
	}

	return theSimilarPath;
}

bool compare_minimumDifferenceLocationArray(MinimumDifferenceLocation const struct1, MinimumDifferenceLocation const struct2)
{
	return struct1.pixelDifference < struct2.pixelDifference;
}

           

Vertical.cpp

#include "pch.h"

Mat Vertical(Mat rock1_, Mat rock2_, int cutRows) {
	Mat rock1 = rock1_;
	Mat rock2 = rock2_;
	int i, j;
	double** Assembly_actually = NULL;
	Mat kimCreate;
	Vec3b** upPicture = NULL;
	Vec3b** downPicture = NULL;
	int rows = rock1.rows;
	int cols = rock2.cols;
	upPicture = (Vec3b**)calloc(cutRows, sizeof(Vec3b*));
	downPicture = (Vec3b**)calloc(cutRows, sizeof(Vec3b*));

for (i = 0; i < cutRows; i++)  // calloc space for pixels from up to down
	{
		upPicture[i] = (Vec3b*)calloc(cols, sizeof(Vec3b));
		downPicture[i] = (Vec3b*)calloc(cols, sizeof(Vec3b));
	}

	Assembly_actually = (double**)calloc(cutRows, sizeof(double*)); // assembly line array contains each pixel weight calculated by RGB
	for (i = 0; i < cutRows; i++)
	{
		Assembly_actually[i] = (double*)calloc(cols, sizeof(double));
	}

	for (i = (rock1.rows - cutRows); i < rock1.rows; i++) {     // initialize upper part overlap pixel
		for (j = 0; j < rock1.cols; j++) {
			Vec3b rock1RGB = rock1.at<Vec3b>(i, j); // get pixel from upper picture
			upPicture[i - (rock1.rows - cutRows)][j] = rock1RGB; // assign pixel to upPicture pixel array
		}
	}

	for (i = 0; i < cutRows; i++) {  // initialize lower part overlap pixel
		for (j = 0; j < rock2.cols; j++) {
			Vec3b rock2RGB = rock2.at<Vec3b>(i, j); // get pixel from lower picture
			downPicture[i][j] = rock2RGB; // assign pixel to downPicture pixel array
		}
	}

	for (i = 0; i < cutRows; i++) {
		for (j = 0; j < cols; j++) {
			// d ==  ( (R1 - R2)^2 + (B1 - B2)^2 + (G1 - G2)^2 )
			Assembly_actually[i][j] = sqrt(pow((upPicture[i][j].val[0] - downPicture[i][j].val[0]), 2) + pow((upPicture[i][j].val[1] - downPicture[i][j].val[1]), 2) + pow((upPicture[i][j].val[2] - downPicture[i][j].val[2]), 2));
		}
	}

	double** f = NULL; // record the value of the shorest distance from starting point to current pixel
	int** l = NULL; // record assembly line path

	f = (double**)calloc(cutRows, sizeof(double*));
	for (i = 0; i < cutRows; i++) {
		f[i] = (double*)calloc(cols, sizeof(double));
	}

	// record assembly line path
	l = (int**)calloc(cols, sizeof(int*));
	for (i = 0; i < cutRows; i++) {
		l[i] = (int*)calloc(cols, sizeof(int));
	}

	for (int i = 0; i < cutRows; i++)
	{
		l[i][0] = i; // initialize first step as itself
	}
	// initialize the pixel value of the first col
	for (i = 0; i < cutRows; i++) {
		f[i][0] = Assembly_actually[i][0]; // initialize first step distance
	}

	for (i = 1; i < cols; i++) {
		for (j = 0; j < cutRows; j++) {
			// if there are three path can be choosed
			if (j != 0 && j != (cutRows - 1)) {
				// if middle path is shortest
				if ((f[j][i - 1] + Assembly_actually[j][i] < f[j - 1][i - 1] + Assembly_actually[j][i]) && (f[j][i - 1] + Assembly_actually[j][i] < f[j + 1][i - 1] + Assembly_actually[j][i])) {
					f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
					l[j][i] = j;
				}
				// if upper path is shortest
				else if ((f[j - 1][i - 1] + Assembly_actually[j][i] < f[j][i - 1] + Assembly_actually[j][i]) && (f[j - 1][i - 1] + Assembly_actually[j][i] < f[j + 1][i - 1] + Assembly_actually[j][i])) {
					f[j][i] = f[j - 1][i - 1] + Assembly_actually[j][i];
					l[j][i] = j - 1;
				}
				// if lower path is shortest
				else if ((f[j + 1][i - 1] + Assembly_actually[j][i] < f[j][i - 1] + Assembly_actually[j][i]) && (f[j + 1][i - 1] + Assembly_actually[j][i] < f[j - 1][i - 1] + Assembly_actually[j][i])) {
					f[j][i] = f[j + 1][i - 1] + Assembly_actually[j][i];
					l[j][i] = j + 1;
				}
				// if there are two path distance are equal, choose middle path by default.  I am a lazy man...
				else {
					f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
					l[j][i] = j;
				}
			}
			// if there are two path can be choosed, the top line or the bottom line
			else {
				// the top line
				if (j == 0 && cutRows > 1) {
					// if middle path is shortest
					if (f[j][i - 1] + Assembly_actually[j][i] < f[j + 1][i - 1] + Assembly_actually[j][i]) {
						f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
						l[j][i] = j;
					}
					// if lower path is shorest
					else if (f[j + 1][i - 1] + Assembly_actually[j][i] < f[j][i - 1] + Assembly_actually[j][i]) {
						f[j][i] = f[j + 1][i - 1] + Assembly_actually[j][i];
						l[j][i] = j + 1;
					}
					// if the middle and lower path are equal ,choose the middle path by default
					else {
						f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
						l[j][i] = j;
					}

				}
				// the bottom line
				else if(j == (cutRows - 1) && cutRows > 1){
					// if middle path is shortest
					if (f[j][i - 1] + Assembly_actually[j][i] < f[j - 1][i - 1] + Assembly_actually[j][i]) {
						f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
						l[j][i] = j;
					}
					// if upper path is shortest
					else if (f[j - 1][i - 1] + Assembly_actually[j][i] < f[j][i - 1] + Assembly_actually[j][i]) {
						f[j][i] = f[j - 1][i - 1] + Assembly_actually[j][i];
						l[j][i] = j - 1;
					}
					// if middle and upper path are euqal, choose the middle path by default
					else {
						f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
						l[j][i] = j;
					}
				}
				// if there is only one path can be choose
				else if (cutRows == 1)
				{
					f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
					l[j][i] = j;
				}
				else {
					exit(-1);
				}
			}
		}
	}

	double minDistance = DBL_MAX;
	int position = -1;
	int lineNum = -1;
	int* boundaryPosition;
	boundaryPosition = (int*)calloc(cols, sizeof(int));  // record the shortest distance path

														 // find the shortest distance from left boundary to right boundary
	for (i = 0; i < cutRows; i++) {
		if (f[i][cols - 1] < minDistance) {
			minDistance = f[i][cols - 1];
			position = i;
		}
		else
			continue;
	}

	// starting from the shortest distance path last pixel
	lineNum = l[position][cols - 1];

	for (i = cols - 1; i >= 0; i--) {
		lineNum = l[lineNum][i];  // from which row to here, upper, middle or lower 
		boundaryPosition[i] = lineNum; // record the shortest distance path each step
	}

	kimCreate.create(rock1.rows + rock2.rows - cutRows, cols, CV_8UC3);  // synthesis upper picture and lower picture for one picture
	for (i = 0; i < (rock1.rows + rock2.rows - cutRows); i++) {
		for (j = 0; j < cols; j++) {
			if (i <= boundaryPosition[j] + (rock1.rows - cutRows)) {  // above the boundary edge
				kimCreate.at<Vec3b>(i, j) = rock1.at<Vec3b>(i, j);
			}
			else {
				kimCreate.at<Vec3b>(i, j) = rock2.at<Vec3b>((i - (rock1.rows - cutRows)), j);
			}
		}
	}
	return kimCreate;
}

           

Horizontal.cpp

#include "pch.h"


Mat Horizontal(Mat rock1_, Mat rock2_, int cutCols)
{
	Mat rock1 = rock1_;
	Mat rock2 = rock2_;
	int i, j;
	double** Assembly_actually = NULL;
	Mat kimCreate;
	Vec3b** leftPicture = NULL;
	Vec3b** rightPicture = NULL;
	int rows = rock1.rows;
	int cols = rock2.cols;

	leftPicture = (Vec3b**)calloc(cutCols, sizeof(Vec3b*));
	rightPicture = (Vec3b**)calloc(cutCols, sizeof(Vec3b*));

	for (i = 0; i < cutCols; i++)
	{
		leftPicture[i] = (Vec3b*)calloc(rows, sizeof(Vec3b));
		rightPicture[i] = (Vec3b*)calloc(rows, sizeof(Vec3b));
	}

	// initialize left picture array, from left to right boundary
	for (i = (rock1.cols - cutCols); i < rock1.cols; i++) {
		for (j = 0; j < rows; j++) {
			Vec3b rock1RGB = rock1.at<Vec3b>(j, i);
			leftPicture[i - (rock1.cols - cutCols)][j] = rock1RGB;
		}
	}

	// initialize right picture array, from left boundary to right
	for (i = 0; i < cutCols; i++) {
		for (j = 0; j < rows; j++) {
			Vec3b rock2RGB = rock2.at<Vec3b>(j, i);
			rightPicture[i][j] = rock2RGB;
		}
	}

	// initialize assembly line array, assembly line array contains each pixel weight in overlapping area
	Assembly_actually = (double**)calloc(cutCols, sizeof(double*));
	for (i = 0; i < cutCols; i++)
	{
		Assembly_actually[i] = (double*)calloc(rows, sizeof(double));
	}


	for (i = 0; i < cutCols; i++) {
		for (j = 0; j < rows; j++) {
			// d ==  ( (R1 - R2)^2 + (B1 - B2)^2 + (G1 - G2)^2 )
			Assembly_actually[i][j] = sqrt(pow((leftPicture[i][j].val[0] - rightPicture[i][j].val[0]), 2) + pow((leftPicture[i][j].val[1] - rightPicture[i][j].val[1]), 2) + pow((leftPicture[i][j].val[2] - rightPicture[i][j].val[2]), 2));
		}
	}

	double** f = NULL; // record the value of the shorest distance from starting point to current pixel
	int** l = NULL; // record assembly line path

	f = (double**)calloc(cutCols, sizeof(double*));
	for (i = 0; i < cutCols; i++) {
		f[i] = (double*)calloc(rows, sizeof(double));
	}
	l = (int**)calloc(cutCols, sizeof(int*));
	for (i = 0; i < cutCols; i++) {
		l[i] = (int*)calloc(rows, sizeof(int));
	}

	for (int i = 0; i < cutCols; i++)
	{
		l[i][0] = i; // initialize first step as itself
	}
	for (i = 0; i < cutCols; i++) {
		f[i][0] = Assembly_actually[i][0]; // initialize first step distance
	}

	for (i = 1; i < rows; i++) {
		for (j = 0; j < cutCols; j++) {
			// if there are three paths can be choosed
			if (j != 0 && j != (cutCols - 1)) {
				// if middle path is the shortest path
				if ((f[j][i - 1] + Assembly_actually[j][i] < f[j - 1][i - 1] + Assembly_actually[j][i]) && (f[j][i - 1] + Assembly_actually[j][i] < f[j + 1][i - 1] + Assembly_actually[j][i])) {
					f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
					l[j][i] = j;
				}
				// if upper path is the shortest path
				else if ((f[j - 1][i - 1] + Assembly_actually[j][i] < f[j][i - 1] + Assembly_actually[j][i]) && (f[j - 1][i - 1] + Assembly_actually[j][i] < f[j + 1][i - 1] + Assembly_actually[j][i])) {
					f[j][i] = f[j - 1][i - 1] + Assembly_actually[j][i];
					l[j][i] = j - 1;
				}
				// if lower path is the shortest path
				else if ((f[j + 1][i - 1] + Assembly_actually[j][i] < f[j][i - 1] + Assembly_actually[j][i]) && (f[j + 1][i - 1] + Assembly_actually[j][i] < f[j - 1][i - 1] + Assembly_actually[j][i])) {
					f[j][i] = f[j + 1][i - 1] + Assembly_actually[j][i];
					l[j][i] = j + 1;
				}
				else {
					f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
					l[j][i] = j;
				}
			}
			// if there are two paths can be choosed
			else {
				// left boundary
				if (j == 0 && cutCols > 1) {
					// if middle path is the shortest path
					if (f[j][i - 1] + Assembly_actually[j][i] < f[j + 1][i - 1] + Assembly_actually[j][i]) {
						f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
						l[j][i] = j;
					}
					// if upper path is the shortest path
					else if (f[j + 1][i - 1] + Assembly_actually[j][i] < f[j][i - 1] + Assembly_actually[j][i]) {
						f[j][i] = f[j + 1][i - 1] + Assembly_actually[j][i];
						l[j][i] = j + 1;
					}
					else {
						f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
						l[j][i] = j;
					}

				}
				// right boundary
				else if(j == (cutCols - 1) && cutCols > 1){
					if (f[j][i - 1] + Assembly_actually[j][i] < f[j - 1][i - 1] + Assembly_actually[j][i]) {
						f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
						l[j][i] = j;
					}
					else if (f[j - 1][i - 1] + Assembly_actually[j][i] < f[j][i - 1] + Assembly_actually[j][i]) {
						f[j][i] = f[j - 1][i - 1] + Assembly_actually[j][i];
						l[j][i] = j - 1;
					}
					else {
						f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
						l[j][i] = j;
					}
				}
				// if there is only one path can be choose
				else if (cutCols == 1) {
					f[j][i] = f[j][i - 1] + Assembly_actually[j][i];
					l[j][i] = j;
				}
				else {
					exit(-1);
				}
			}
		}
	}

	double minDistance = DBL_MAX;
	int position = -1;
	int lineNum = -1;
	int* boundaryPosition;
	boundaryPosition = (int*)calloc(rows, sizeof(int));

	// find the shortest path from left boundary to right boundary
	for (i = 0; i < cutCols; i++) {
		if (f[i][rows - 1] < minDistance) {
			minDistance = f[i][rows - 1];
			position = i;
		}
		else
			continue;
	}

	//lineNum = l[rows - 1][position];
	lineNum = l[position][rows - 1];
	for (i = rows - 1; i >= 0; i--) {
		lineNum = l[lineNum][i];
		boundaryPosition[i] = lineNum;
	}

	/*
	The codes below are not in line with human thinking habits,
	it's difficult to understand them
	*/

	// create a picture , note the paras order --  rows, cols, type
	//kimCreate.create(rows, 2 * cols - cutCols, CV_8UC3);
	kimCreate.create(rows, rock1.cols + rock2.cols - cutCols, CV_8UC3);
	// assign the new picture from left to right and up to down
	for (i = 0; i < rows; i++) {
		for (j = 0; j < (rock1.cols + rock2.cols - cutCols); j++) {
			if (j <= boundaryPosition[i] + (rock1.cols - cutCols)) {  // at the left of the boundary edge
				kimCreate.at<Vec3b>(i, j) = rock1.at<Vec3b>(i, j);
			}
			else {
				kimCreate.at<Vec3b>(i, j) = rock2.at<Vec3b>(i, (j - (rock1.cols - cutCols)));
			}

		}
	}

	return kimCreate;
}

           

欢迎批评指正!