现将一张图片分成n*n张图片,每张图片宽度与高度一致,要求用CImage将随机排序的图片拼回原状
讲道理我也是刚刚才接触这些内容的,上手之后第一个问题就是string怎么转换为LPCTSTR使得CImage可以构造,具体解决是通过cstring作为中间转换
String str = "abc";
CString resultDir = str.c_str();
LPCTSTR destFilePath = (LPCTSTR)resultDir;
然后是权值的计算,一开始的解决方案是分别计算bgr的平方差,再求和,这样就导致了相邻的边却不是最小值这种情况(可跑出案例中前两种情况),于是听说了灰度计算,尝试了一下,即可跑出所有案例
最后是构造最后的n*n的数组,一开始的想法是从图片列表数组中按顺序插入数组中,后来通过先找左上角的图片(即左边上边无相邻图片)实现
#include
#include
#include
#include
#include
#include
#include
using namespace std;
class Image{
public:
CImage src;
BYTE *pData;//存放所有的rgb
BYTE **lineP = new BYTE *[4];//存放所有边上的rgb
int width, height, bpp, pitch;//图片参数
int next[4] = { -1,-1,-1,-1 };//上右下左四个方向的图片
double **linePower;//四条边上与其他图片的权值
void load(LPCTSTR file) {
src = CImage();
src.Load(file);//加载图片
pData = (BYTE *)src.GetBits();//获取每个点
//获取部分参数
width = src.GetWidth();
height = src.GetHeight();
bpp = src.GetBPP();
pitch = src.GetPitch();
//加载边界
loadLine();
}
void loadLine() {
lineP[0] = new BYTE[width];//上边0
lineP[1] = new BYTE[height];//右边1
lineP[2] = new BYTE[width];//下边2
lineP[3] = new BYTE[height];//左边3
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int p[2] = { -1 ,-1};
if (x == 0) {
p[0] = 3;//左边
}else if (x == width - 1)
{
p[0] = 1;//右边
}
if (y == 0){
p[1] = 0;//上边
}else if (y == height - 1)
{
p[1] = 2;//上边
}
//参数0 左右边 参数1 上下边
for (int i = 0; i < 2; i++)
{
if (p[i] != -1) {
BYTE b = *(pData + pitch * y + x * bpp / 8 + 0);
BYTE g = *(pData + pitch * y + x * bpp / 8 + 1);
BYTE r = *(pData + pitch * y + x * bpp / 8 + 2);
lineP[p[i]][i == 0 ? y : x] = b * 0.114 + g * 0.587 + r * 0.299;
}
}
}
}
}
};
void join(LPCTSTR srcFilePath[], LPCTSTR destFilePath, int cnt)
{
Image *srcImage = new Image[cnt];
CImage destImage;
int sqr = sqrt(cnt);//X*X
for (int i = 0; i < cnt; i++)
{
srcImage[i].load(srcFilePath[i]);
srcImage[i].linePower = new double *[cnt];//其他cnt张图片的边界权值
}
int height = srcImage[0].height, width = srcImage[0].width, bpp = srcImage[0].bpp;
int length[4] = {width,height,width,height};//用于记录四条边的长度
destImage.Create(width * sqr, height * sqr, bpp);//创建新的图片
//计算每张图片每条边与别的图片的平方差
for (int i = 0; i < cnt; i++)
{
for (int j = 0; j < cnt; j++)
{
srcImage[i].linePower[j] = new double[4];//四条边的权值
if (i == j) {
for (int line = 0; line < 4; line++)
{
//-1为跳过标识
srcImage[i].next[line] = -1;
}
continue;//当前图片跳过本次循环
}
for (int line = 0; line < 4; line++)
{
int otherLine = (line + 2) % 4;//0->2 1->3 2->0 3->1
int count = 0;//平方差之和
for (int point = 0; point < length[line]; point++)
{
count += pow(srcImage[i].lineP[line][point] - srcImage[j].lineP[otherLine][point], 2);
}
srcImage[i].linePower[j][line] = count / length[line];//平均平方差
}
}
for (int line = 0; line < 4; line++)
{
int min = -1;//标记
for (int j = 0; j < cnt; j++)
{
if (i == j) continue;//本张图片跳过
if (min==-1 || srcImage[i].linePower[min][line] > srcImage[i].linePower[j][line]) {
min = j;//权值最小的图片下标
}
}
srcImage[i].next[line] = min;//该条边上权值最小的图片
}
}
//判断是否是彼此的唯一
for (int i = 0; i < cnt; i++)
{
for (int line = 0; line < 4; line++)
{
if (srcImage[i].next[line] != -1)
{
if (i != srcImage[srcImage[i].next[line]].next[(line + 2) % 4])
{
srcImage[i].next[line] = -1;//不是彼此的唯一最小则打回原形
}
}
}
}
/**
string tip[4] = {"上","右","下","左"};
for (int i = 0; i < cnt; i++)
{
cout << "第" << i << "张图片" ;
for (int line = 0; line < 4; line++)
{
cout << endl<< tip[line] << srcImage[i].next[line] << '\t' << endl;
for (int j = 0; j < cnt; j++)
{
if (i == j) continue;
cout << srcImage[i].linePower[j][line] << '\t';
}
}
cout << endl;
}**/
int begin;//找到右下角的图片
for (int i = 0; i < cnt; i++)
{
if (srcImage[i].next[2] == -1 && srcImage[i].next[1] == -1)
{
begin = i;
break;
}
}
//声明一个用于存储九宫格下标的二维数组
int **despair = new int*[sqr];
for (int i = 0; i < sqr; i++) {
despair[i] = new int[sqr];
}
for (int i = sqr-1; i >=0; i--) {
for (int j = sqr - 1; j >=0; j--) {
if (i== sqr - 1) {
if (j == sqr - 1)
{
despair[i][j] = begin; //右下角赋值
}
else
{
despair[i][j] = srcImage[despair[i][j + 1]].next[0];//其余右边第一列
}
}
else
{
despair[i][j] = srcImage[despair[i + 1][j]].next[3];
}
}
}
for (int i = 0; i < sqr; i++)
{
for (int j = 0; j < sqr; j++)
{
cout << despair[j][i] << '\t';
}
cout << endl;
}
for (int i = 0; i < sqr; i++)
{
for (int j = 0; j < sqr; j++)
{
srcImage[despair[j][i]].src.Draw(destImage.GetDC(), width*j, height*i, width, height, 0, 0, width, height);
destImage.ReleaseDC();
}
}
destImage.Save(destFilePath);
}
/*
path: 指定目录
files: 保存结果
fileType: 指定的文件格式,如 .jpg
*/
void getAllFiles(string path, vector& files, string fileType)
{
//文件句柄
long hFile = 0;
//文件信息
struct _finddata_t fileinfo;
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*" + fileType).c_str(), &fileinfo)) != -1) {
do {
//保存文件的全路径
files.push_back(p.assign(path).append("\\").append(fileinfo.name));
} while (_findnext(hFile, &fileinfo) == 0); //寻找下一个,成功返回0,否则-1
_findclose(hFile);
}
}
//----------------------------------------------------------------------------------
int main()
{
string fileName[4] = {"大作业第1组测试案例2x2","大作业第2组测试案例3x3" ,"大作业第3组测试案例6x6" ,"大作业第4组测试案例3x3" };
string dir = "C:\\Users\\xjc82\\Desktop\\Day4\\";
for (int i = 0; i < 4; i++) {
vector temp;
getAllFiles(dir+fileName[i], temp, ".jpg");//读取图片列表
int cnt = temp.size();//图片的数量
//将图片地址String转为LPCTSTR
LPCTSTR *srcFilePath = new LPCTSTR[cnt];
CString *cs = new CString[cnt];
for (int i = 0; i < cnt; i++)
{
cs[i] = temp[i].c_str();
srcFilePath[i] = (LPCTSTR)cs[i];
}
//将导出图片地址String转为LPCTSTR
CString resultDir = (dir + fileName[i] + ".jpg").c_str();
LPCTSTR destFilePath = (LPCTSTR)resultDir;
join(srcFilePath, destFilePath, cnt);
}
return 0;
}
案例的图片素材:案例.rar