你能帮我找到适合图像大小调整的算法吗?我有一个数字的图像。最大尺寸为200x200,我需要获得尺寸为15x15甚至更小的图像。图像是单色(黑白),结果应该相同。这是关于我的任务的信息。
我已经尝试过一种算法,这里是
// xscale, yscale - decrease/increase rate
for (int f = 0; f<=49; f++)
{
for (int g = 0; g<=49; g++)//49+1 - final size
{
xpos = (int)f * xscale;
ypos = (int)g * yscale;
picture3[f][g]=picture4[xpos][ypos];
}
}
但它不适用于图像的减少,这是我之前的目标。 你能帮我找一个可以解决这个问题的算法(质量一定不是完美的,速度甚至不重要)。考虑到我是新手的事实,关于它的一些信息也是完美的。当然,一小段c / c ++代码(或库)也是完美的。
编辑: 我找到了算法。它是否适合压缩200到20?
答案 0 :(得分:10)
一般方法是过滤输入以生成较小的尺寸,并将阈值转换为单色。要实现的最简单的过滤器是简单的平均值,它通常会产生OK结果。 Sinc filter在理论上是最好的,但它实现起来是不切实际的,并且具有通常不期望的振铃伪像。还有许多其他过滤器,例如Lanczos或Tent(这是Bilinear的广义形式)。
这是一个与阈值相结合的平均过滤器版本。假设picture4
是像素值为0或1的输入,输出为picture3
的格式相同。我还假设x
是最不重要的维度,与通常的数学符号相反,与你问题中的坐标相反。
int thumbwidth = 15;
int thumbheight = 15;
double xscale = (thumbwidth+0.0) / width;
double yscale = (thumbheight+0.0) / height;
double threshold = 0.5 / (xscale * yscale);
double yend = 0.0;
for (int f = 0; f < thumbheight; f++) // y on output
{
double ystart = yend;
yend = (f + 1) / yscale;
if (yend >= height) yend = height - 0.000001;
double xend = 0.0;
for (int g = 0; g < thumbwidth; g++) // x on output
{
double xstart = xend;
xend = (g + 1) / xscale;
if (xend >= width) xend = width - 0.000001;
double sum = 0.0;
for (int y = (int)ystart; y <= (int)yend; ++y)
{
double yportion = 1.0;
if (y == (int)ystart) yportion -= ystart - y;
if (y == (int)yend) yportion -= y+1 - yend;
for (int x = (int)xstart; x <= (int)xend; ++x)
{
double xportion = 1.0;
if (x == (int)xstart) xportion -= xstart - x;
if (x == (int)xend) xportion -= x+1 - xend;
sum += picture4[y][x] * yportion * xportion;
}
}
picture3[f][g] = (sum > threshold) ? 1 : 0;
}
}
我现在已经测试了这段代码。这是输入200x200图像,然后是最近邻居减少到15x15(在Paint Shop Pro中完成),然后是此代码的结果。我会让你决定哪一个更忠实于原作;如果原版有一些细节,那么差异会更明显。
答案 1 :(得分:3)
由于你使用图书馆很好,你可以查看imagemagick C++ bindings。
您也可以以pbm
之类的简单格式输出图像,然后调用imagemagick命令调整其大小:
system("convert input.pbm -resize 10x10 -compress none output.pbm");
示例输出文件(注意:您不需要为每一行使用新行):
P1
20 20
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0
0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0
0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0
0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
输出文件:
P1
10 10
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 0 1 1 0
0 0 0 0 1 0 0 1 1 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 1 1 1 1
1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0
答案 2 :(得分:3)
我发现了双线性插值的实现。 C代码。
假设:
a - 一个主数组(我们需要拉伸/压缩)指针。
oldw - 主要宽度
oldh - 初级身高
b - 辅助数组(我们在压缩/拉伸后获得)指针
neww - 辅助宽度
newh - seconday height
#include <stdio.h>
#include <math.h>
#include <sys/types.h>
void resample(void *a, void *b, int oldw, int oldh, int neww, int newh)
{
int i;
int j;
int l;
int c;
float t;
float u;
float tmp;
float d1, d2, d3, d4;
u_int p1, p2, p3, p4; /* nearby pixels */
u_char red, green, blue;
for (i = 0; i < newh; i++) {
for (j = 0; j < neww; j++) {
tmp = (float) (i) / (float) (newh - 1) * (oldh - 1);
l = (int) floor(tmp);
if (l < 0) {
l = 0;
} else {
if (l >= oldh - 1) {
l = oldh - 2;
}
}
u = tmp - l;
tmp = (float) (j) / (float) (neww - 1) * (oldw - 1);
c = (int) floor(tmp);
if (c < 0) {
c = 0;
} else {
if (c >= oldw - 1) {
c = oldw - 2;
}
}
t = tmp - c;
/* coefficients */
d1 = (1 - t) * (1 - u);
d2 = t * (1 - u);
d3 = t * u;
d4 = (1 - t) * u;
/* nearby pixels: a[i][j] */
p1 = *((u_int*)a + (l * oldw) + c);
p2 = *((u_int*)a + (l * oldw) + c + 1);
p3 = *((u_int*)a + ((l + 1)* oldw) + c + 1);
p4 = *((u_int*)a + ((l + 1)* oldw) + c);
/* color components */
blue = (u_char)p1 * d1 + (u_char)p2 * d2 + (u_char)p3 * d3 + (u_char)p4 * d4;
green = (u_char)(p1 >> 8) * d1 + (u_char)(p2 >> 8) * d2 + (u_char)(p3 >> 8) * d3 + (u_char)(p4 >> 8) * d4;
red = (u_char)(p1 >> 16) * d1 + (u_char)(p2 >> 16) * d2 + (u_char)(p3 >> 16) * d3 + (u_char)(p4 >> 16) * d4;
/* new pixel R G B */
*((u_int*)b + (i * neww) + j) = (red << 16) | (green << 8) | (blue);
}
}
}
希望它对其他用户有用。但是,我仍然怀疑它是否会在我的情况下工作(当不是stratching,而是压缩数组)。有什么想法吗?
答案 3 :(得分:2)
我想,你需要Interpolation。有很多算法,例如你可以使用Bilinear interpolation
答案 4 :(得分:2)
要正确缩小图像尺寸,您应该将图像划分为方形像素块,然后使用类似Bilinear Interpolation的内容,以便找到应该替换NxN像素块的像素的正确颜色。重新进行插值。
由于我不太擅长数学,我不会试着给你一个代码如何的例子。对不起:(
答案 5 :(得分:2)
如果你使用Win32,那么StretchBlt函数可能会有所帮助。
StretchBlt函数将位图从源矩形复制到目标矩形,如有必要,拉伸或压缩位图以适合目标矩形的尺寸。系统根据当前在目标设备上下文中设置的拉伸模式拉伸或压缩位图。
答案 6 :(得分:0)
将200x200
图片缩小到100x100
的一种方法是沿每行和每列拍摄第2个像素。我将让您滚动自己的代码,缩小尺寸,而不是原始尺寸的除数。我不保证这种方法适用于您的问题。