将灰度图像转换为更小的“逐像素”灰度图像

2024-04-26 06:47:57 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个很大的图像,但是1个正方形代表很多像素值,但是我想要一个只有1个像素的特定值的图像。正方形的大小不尽相同。在

有些柱子窄一些,有些较宽。以下是大形象的一部分:

enter image description here

你可以看到左手边的方块比右手边的大。这就是问题所在!在

实际图像:

enter image description here

例如,使用下面的代码,当我试图将我的图像逐像素地转换为一个更小的像素时,我得到了这个,这与最初的图片完全不同。在

enter image description here

from PIL import Image
import numpy as np

img = Image.open('greyscale_intense.png').convert('L')  # convert image to 8-bit grayscale
WIDTH, HEIGHT = img.size

a = list(img.getdata()) # convert image data to a list of integers
# convert that to 2D list (list of lists of integers)
a = np.array ([a[offset:offset+WIDTH] for offset in range(0, WIDTH*HEIGHT, WIDTH)])

print " "
print "Intial array from image:"  #print as array
print " "
print a

rows_mask = np.insert(np.diff(a[:, 0]).astype(np.bool), 0, True)
columns_mask = np.insert(np.diff(a[0]).astype(np.bool), 0, True)
b = a[np.ix_(rows_mask, columns_mask)]


print " "
print "Subarray from Image:"  #print as array
print " "
print b


print " "
print "Subarray from Image (clearer format):"  #print as array
print " "
for row in b: #print as a table like format
    print(' '.join('{:3}'.format(value) for value in row))

img = Image.fromarray(b, mode='L')

img.show()

我在代码中所做的是从初始图像创建一个数组,然后通过忽略一个重复的值,创建一个没有重复值的子数组。新的图像就是用这个构造的。在

例如,对于此图像:

enter image description here

我得到的结果是:

enter image description here

从数组中可以看到38被重复了9次,而27被重复了8次。。。在

我的最终目标是对彩色RGB图像进行相同的处理,如图所示。在

enter image description here

请帮忙!在


Tags: tofrom图像imageconvertimgasnp
3条回答

如果我做对了,你想得到最近邻放大图像的原始分辨率。所以该怎么办:

  1. 计算水平网格大小

    如果你新的原始分辨率和放大过程,你可以直接计算平方大小。但是,如果你不知道缩放是如何进行的,那么更安全的方法是从图像中计算出来。在

    因此,您需要做的是计算从x=0开始的所有水平线中有多少后续像素具有相同的颜色。记住最小的一个将是第一个列宽。在

    现在执行相同的操作,但从x+column_width开始,然后下一列直到获得所有列宽。

  2. 计算垂直网格大小

    它与#1相同,但处理的是从y=0开始的垂直线。

  3. 创建和复制新图像

    来自1,#2的列数和行数将为您提供图像的原始分辨率,因此请创建相同大小的新图像。在

    然后只需设置其每个像素对应的网格正方形中间像素颜色。

这里小<强> C++ +VCL <强>实例(对不起,不是Python编码器):

void rescale_back(Graphics::TBitmap *bmp)
    {
    int *gx,*gy,nx,ny;  // original image
    int x,y,xs,ys;      // rescaled image
    int xx,yy,n;
    DWORD **p;          // direct pixel acces p[y][x]
    // prepare buffers
    xs=bmp->Width;
    ys=bmp->Height;
    p =new DWORD*[ys];
    gx=new int[xs];
    gy=new int[ys];
    // enable direct pixel access (VCL stuff ignore)
    bmp->HandleType=bmDIB;
    bmp->PixelFormat=pf32bit;
    for (y=0;y<ys;y++) p[y]=(DWORD*)bmp->ScanLine[y];
    // compute column sizes
    for (nx=0,x=0;x<xs;)        // loop columns
        {
        for (n=0,y=0;y<ys;y++)  // find smallest column starting from x
            {
            for (xx=x;xx<xs;xx++) if (p[y][x]!=p[y][xx]) break;
            xx-=x; if ((!n)||(n>xx)) n=xx;
            }
        gx[nx]=x+(n>>1); nx++; x+=n;    // store mid position of column
        }
    // compute row sizes
    for (ny=0,y=0;y<ys;)        // loop rows
        {
        for (n=0,x=0;x<xs;x++)  // find smallest row starting from y
            {
            for (yy=y;yy<ys;yy++) if (p[y][x]!=p[yy][x]) break;
            yy-=y; if ((!n)||(n>yy)) n=yy;
            }
        gy[ny]=y+(n>>1); ny++; y+=n;    // store mid position of row
        }
    // copy data
    for (yy=0;yy<ny;yy++)
     for (xx=0;xx<nx;xx++)
      p[yy][xx]=p[gy[yy]][gx[xx]];
    // crop
    bmp->SetSize(nx,ny);
    // release buffers
    delete[] p;
    delete[] gx;
    delete[] gy;
    }

在重复问题的输入图像上使用:

in

输出结果:

out

如果需要对双线性过滤图像执行此操作,请参见:

这里的结果很可能是一些图像放大的结果,使用非整数比例因子和最近邻重采样规则。所以所有这些大像素可能有相同的单位大小。在

要获得精确的像素宽度(在垂直方向重复以下所有步骤),只需画一条水平线并找到不连续点就足够了。结果可能是两个相邻的像素有相同的值,所以你必须在其他地方找到不连续性。由于您对宽度有很好的估计,所以很容易检测到这种情况。在


实际上,在知道平均像素宽度的情况下,甚至可以猜测变化的位置:它们将发生在floor(nw)或者可能是{},其中{}和{}是需要确定的有理数。在

使用上述方法,您可以绘制n和转换位置之间的关系。在

我不想写代码,但你也可以:

a)“滚动”(see here)将图像向右滚动一个像素,然后从原始图像中差分(减去),然后使用np.where查找大于零的所有像素,因为这些是您的“正方形”结束处的“边缘”,即一个像素与其相邻像素不同。然后找到任何元素都不为零的列,并使用这些列作为索引从原始图像中获取值。然后将图像向下滚动一个像素,找到感兴趣的水平行,然后重复上述操作,但对于水平的“edges”。在

或者

然后用一个差分的像素代替它的邻域,然后用一个差分的图像来代替它。自我与右翼邻居之间的区别的核心是:

0  0  0
0 -1  1
0  0  0 

而下面的自我和邻居之间的区别是:

^{pr2}$

创建和应用内核的枕头文档是here。在


我将在命令行演示ImageMagick的含义。首先,我克隆你的图像,在拷贝中我将图像向右滚动一个像素,然后我将滚动结果与原始图像不同,并生成一个新的输出图像-标准化以获得更大的对比度。在

^{3}$

enter image description here

现在我再次执行同样的操作,但将图像垂直滚动一个像素:

convert CwinB.png \( +clone -roll +0+1 \) -compose difference -composite -normalize v.png

enter image description here

现在将这两种方法结合起来,取每个像素处较亮的图像:

convert [vh].png -compose lighten -composite z.png

enter image description here

希望你能看到它找到你的正方形的边缘,你现在可以选择任何一行,或列,完全是黑色来找到你的原始像素。在

相关问题 更多 >