将灰度图像逐个像素地转换为更小的像素'灰度图像

时间:2018-06-19 09:30:16

标签: python numpy opencv image-processing python-imaging-library

我的图像质量很大但是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

请帮忙!

3 个答案:

答案 0 :(得分:0)

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

要获得精确的像素宽度(重复沿垂直方向的所有像素宽度),只需画一条水平线并找到不连续点即可。可能会发现两个相邻像素具有相同的值,因此您必须在其他位置找到不连续点。由于您对宽度的估算非常好,因此很容易检测到这种情况。


实际上,甚至有可能知道平均像素宽度来猜测变化的位置:它们将在floor(nw)或可能在floor(nw+c)处出现,其中w和{{1 }}是您需要确定的有理数。

使用上述方法,可以绘制n与过渡位置之间的关系。

答案 1 :(得分:0)

我不想编写代码,但是您可以:

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

b)用差分内核对图像进行卷积,该内核用右边的像素与其相邻像素之间的差异替换每个像素,然后按上述步骤进行操作。自我和右边邻居之间差异的核将是:

0  0  0
0 -1  1
0  0  0 

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

0  0  0
0 -1  0
0  1  0

用于创建内核和应用内核的Pillow文档为here


我将在命令行中使用 ImageMagick 来说明我的意思。首先,我克隆您的图像,然后在副本中将图像向右滚动一个像素,然后将滚动结果与原始图像不同,然后制作一个新的输出图像-标准化以获得更大的对比度。

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

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

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

答案 2 :(得分:0)

如果我做对了,您想获得最近邻居放大图像的原始分辨率。那么该怎么做:

  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

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