+
||
程序:
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;
}
欢迎批评指正!