【问题标题】:How do I convert pixels/numpy-array into vector-dots?如何将像素/numpy-array 转换为矢量点?
【发布时间】:2020-06-29 18:10:08
【问题描述】:

我想将灰度图片的像素值转换为矢量点,以便像素的灰度值确定相应点的半径。 但是我完全卡住了,这个项目必须在周日完成,我现在真的很绝望

背景: 对于我的大学课程“python 简介”,我想用 python 构建一个“rasterbator”(https://rasterbator.net/)的无耻副本(但以更原始的方式) .

我想如何解决这个问题?: 我用 PIL 加载图像,使其成为灰度图像并将其转换为 numpy 数组。然后我将数组分割成许多小正方形数组(每个预期点一个段),计算每个数组的平均值并将其重新组合到一个数组中,该数组现在比原始数组小得多。到那时,我能够做到(但我花了很长时间)。 现在我想用点“替换”像素并创建几个 PDF,这样您就可以打印、粘合在一起并制作一张大海报。

这种方法可行吗?还是我找错树了?

我是一个该死的 python 初学者。 python的问题是对我来说,有太多我不知道的模块。可能答案真的很简单,但我根本不知道在哪里看。如果有人能告诉我,我是否走在正确的道路上或指向正确的方向,我将不胜感激。

提前致谢

这里是我目前管理的代码(虽然不多)

from PIL import Image as img
import numpy as np

greyscale = np.asarray(img.open("test.jpg").convert("L")) #load picture into array and make it greyscale

end_width = 1500 # chosen width of final picture in mm (will be with kwargs later on)
dot_size = 13 #chosen dot-size of final pictutre in mm (will be with kwargs later on)
estimate_dot_count_x = int(np.ceil(end_width/dot_size)) # estimates the "horizontal resolution"

pixel_in_segment = int(np.ceil(greyscale.shape[1]/estimate_dot_count_x)) #calculates the edge length of a segment
W=pixel_in_segment #just for shorter formular later on 

estimate_dot_count_y = int(np.ceil(greyscale.shape[0]/pixel_in_segment)) # estimates the "vertical resolution"
final_dot_count_x=int(np.ceil(greyscale.shape[1]/W)) #final horizontal resolution for shape of new array
final_dot_count_y=int(np.ceil(greyscale.shape[0]/W)) #final vertical resolution for shape of new array
#slice array into multiple pieces
tiles = [greyscale[x:x+W,y:y+W] for x in range(0,greyscale.shape[0],W) for y in range(0,greyscale.shape[1],W)]
#calculate mean values of each segment an safe it to list
average_list = []
for pixel in tiles:
    result=int(np.mean(pixel))
    average_list.append(result)
#convert list back into an array
downscale=np.asarray(average_list, dtype=int).reshape(final_dot_count_y,final_dot_count_x)

编辑: 不知何故,我设法将数组绘制到矢量点:

#inverse and normalize gray value so That I can multiply with max dot size
for ix,iy in np.ndindex(downscale.shape):
    downscale[ix,iy]= float(1-downscale[ix,iy]*(1/255))

reportlab 是我一直在寻找的关键...

from reportlab.lib.units import mm
from reportlab.pdfgen import canvas
#making dots
def printing(c):
    c.translate(spacing*0.5,imh-(spacing*0.5))
    for ix,iy in np.ndindex(downscale.shape):
       c.circle(iy*(spacing), ix*(-spacing), downscale[ix, iy]*max_dot_size, stroke=1, fill=1)
c = canvas.Canvas("hello.pdf", pagesize=(imwidth, imhight))
printing(c)
c.showPage()
c.save()

这就提出了一个问题: 如何告诉reportlab,我想以通用打印机格式('letter' 或'A4')将这个大画布(尺寸为 2m x1.5m)打印到多页?

【问题讨论】:

    标签: arrays python-3.x image vector-graphics reportlab


    【解决方案1】:

    仅供参考,我可以重建“Rasterbator” 代码可能有点混乱,并且缺少错误处理,但我工作得非常好,而且我没时间了。所以这就是我上传的。 一些变量是德语,对不起。我倾向于混合语言。必须改变它。

    需要模块reportlab

    from PIL import Image as img
    import numpy as np
    from reportlab.lib.units import mm
    from reportlab.pdfgen import canvas
    from reportlab.lib.pagesizes import A4
    from math import sqrt
    
    
    #load image to array and make it greyscale
    input_file = input("Please enter the image file you want do convert: ")
    greyscale = np.asarray(img.open(input_file).convert("L"))
    
    print("\n"+"Image resolution is " + str(greyscale.shape[1]) + "x" + str(greyscale.shape[0]))
    #defining width of poster
    print("\n"+"please enter the target width of your poster")
    print("remember, the dimensions of an A4 sheet is: 210mm x 297mm ")
    end_width= int(input("target poster width in mm: "))
    #defining grid size of poster
    print('\n'+'The distance between 2 Points in the grid. Choose the grid size wisely in relation to the size of your poster '+'\n'+'recommended size is 7-12mm')
    print('please notice, that the maximum dot size is higher than the grid size (factor 1.4) to allow pure black coverage')
    grid_size = int(input("Please enter the target grid size in mm: "))
    #select orientation
    print("your sheets can be arranged in portrait or landscape orientation")
    print_format = input("Please enter p for portrait or l for landscape :")
    
    if print_format=="l":
        height, width = A4 #Landscape
    elif print_format=="p":
        width, height = A4 #Portrait
    else:
        print("-invalid input-  continuing with default (portrait)")
        width, height = A4 #Portrait
    
    
    
    # calculates the "x-resolution" as a base for further calculations
    estimate_dot_count_x = int(np.ceil(end_width/grid_size)) 
    
    #calculates the size of a segment in array
    pixel_in_segment = int(np.ceil(greyscale.shape[1]/estimate_dot_count_x))
    W=pixel_in_segment #obsolete, just for shorter formulars later on
    
    #final horizontal resolution for shape of new array
    final_dot_count_x=int(np.ceil(greyscale.shape[1]/W))
    #final vertical resolution for shape of new array
    final_dot_count_y=int(np.ceil(greyscale.shape[0]/W))
    #slice array into multiple pieces
    tiles = [greyscale[x:x+W,y:y+W] for x in range(0,greyscale.shape[0],W) for y in range(0,greyscale.shape[1],W)]
    
    #calculate mean values of each segment an safe it to list
    average_list = []
    for pixel in tiles:
        result=int(np.mean(pixel))
        average_list.append(result)
    
    #convert list back into an array 
    downscale=np.asarray(average_list, dtype=float).reshape(final_dot_count_y,final_dot_count_x)
    
    print('\n'+'downscaling picture...')
    
    #prepare data to work in point scale
    spacing=grid_size*mm
    #calculating final poster size
    imw=downscale.shape[1]*spacing
    imh=downscale.shape[0]*spacing
    #scaling dots to allow complete coverage with black for very dark areas
    max_dot_size=spacing*sqrt(2)/2
    
    #inverse and normalize pixel value
    for ix,iy in np.ndindex(downscale.shape):
        downscale[ix,iy]= float(1-downscale[ix,iy]*(1/255))
    
    
    print('\n'+'printing image to pdf...')
    #calculate numer of A4 sheets required for printing
    pages_w = int(np.ceil(imw/width))
    pages_h = int(np.ceil(imh/height))
    #stuff for showing progress while printing
    seitenzahl=0
    gesamtseitenzahl = pages_w*pages_h
    
    
    def printing(c):
        #auxillary variables for iterating over poster
        left=width*x
        top=height*y
        #iterate instructions
        c.translate(-left+spacing*0.5,imh-top+(spacing*0.5))
        #drawing the circles
        for ix,iy in np.ndindex(downscale.shape):
            c.circle(iy*(spacing), ix*(-spacing), downscale[ix, iy]*max_dot_size, stroke=1, fill=1)
    
    #setting canvas properties
    c = canvas.Canvas(str(input_file)+".pdf", pagesize=(width, height))
    #make pages
    for x in range(pages_w):
        for y in range(pages_h):
            #progress documentation
            seitenzahl = seitenzahl+1
            #call printing function
            printing(c)
            #progress documentation
            print("printing page " + str(seitenzahl)+ " of " + str(gesamtseitenzahl))
            c.showPage()
    
    #save to disk        
    print('\n'+'save to disk...')
    c.save()
    print('...PDF successfully saved as ' + str(input_file)+".pdf")
    

    【讨论】:

      【解决方案2】:

      而不是“将图像切成小方块并计算每个方块的平均值”...如果您想要 80 个点通过 60 个点向下,只需像这样使用resize():

      im_resized = im.resize((80, 60))
      

      【讨论】:

      • 是的,所以我之前的所有思考和工作都是无用的,因为它太容易了。但我还是按原样保留了它,因为无论如何我都必须对数组进行一些计算。不过谢谢你的建议,下次我会去那条路
      猜你喜欢
      • 2018-02-15
      • 1970-01-01
      • 2020-08-03
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多