[Python] Compromise between quality and file size, how to save a very detailed image into a...

Discussão em 'Python' iniciado por Stack, Setembro 15, 2024.

  1. Stack

    Stack Membro Participativo

    I am facing a small (big) problem: I want to generate a high resolution speckle pattern and save it as a file that I can import into a laser engraver. Can be PNG, JPEG, PDF, SVG, or TIFF.

    My script does a decent job of generating the pattern that I want:

    The user needs to first define the inputs, these are:

    ############
    # INPUTS #
    ############
    dpi = 1000 # dots per inch
    dpmm = 0.03937 * dpi # dots per mm
    widthOfSampleMM = 50 # mm
    heightOfSampleMM = 50 # mm
    patternSizeMM = 0.1 # mm
    density = 0.75 # 1 is very dense, 0 is not fine at all
    variation = 0.75 # 1 is very bad, 0 is very good
    ############


    After this, I generate the empty matrix and fill it with black shapes, in this case a circle.

    # conversions to pixels
    widthOfSamplesPX = int(np.ceil(widthOfSampleMM*dpmm)) # get the width
    widthOfSamplesPX = widthOfSamplesPX + 10 - widthOfSamplesPX % 10 # round up the width to nearest 10
    heightOfSamplePX = int(np.ceil(heightOfSampleMM*dpmm)) # get the height
    heightOfSamplePX = heightOfSamplePX + 10 - heightOfSamplePX % 10 # round up the height to nearest 10
    patternSizePX = patternSizeMM*dpmm # this is the size of the pattern, so far I am going with circles
    # init an empty image
    im = 255*np.ones((heightOfSamplePX, widthOfSamplesPX), dtype = np.uint8)
    # horizontal circle centres
    numPoints = int(density*heightOfSamplePX/patternSizePX) # get number of patterns possible
    if numPoints==1:
    horizontal = [heightOfSamplePX // 2]
    else:
    horizontal = [int(i * heightOfSamplePX / (numPoints + 1)) for i in range(1, numPoints + 1)]
    # vertical circle centres
    numPoints = int(density*widthOfSamplesPX/patternSizePX)
    if numPoints==1:
    vertical = [widthOfSamplesPX // 2]
    else:
    vertical = [int(i * widthOfSamplesPX / (numPoints + 1)) for i in range(1, numPoints + 1)]
    for i in vertical:
    for j in horizontal:
    # generate the noisy information
    iWithNoise = i+variation*np.random.randint(-2*patternSizePX/density, +2*patternSizePX/density)
    jWithNoise = j+variation*np.random.randint(-2*patternSizePX/density, +2*patternSizePX/density)
    patternSizePXWithNoise = patternSizePX+patternSizePX*variation*(np.random.rand()-0.5)/2
    cv2.circle(im, (int(iWithNoise),int(jWithNoise)), int(patternSizePXWithNoise//2), 0, -1) # add circle


    After this step, I can get im, here's a low quality example at dpi=1000:

    [​IMG]

    And here's one with my target dpi (5280):

    [​IMG]

    Now I would like to save im in a handlable way at high quality (DPI>1000). Is there any way to do this?


    Stuff that I have tried so far:

    1. plotting and saving the plot image with PNG, TIFF, SVG, PDF with different DPI values plt.savefig() with different dpi's
    2. cv2.imwrite() too large of a file, only solution here is to reduce DPI, which also reduces quality
    3. SVG write from matrix: I developed this function but ultimately, the files were too large:

    import svgwrite
    def matrix_to_svg(matrix, filename, padding = 0, cellSize=1):
    # get matrix dimensions and extremes
    rows, cols = matrix.shape
    minVal = np.min(matrix)
    maxVal = np.max(matrix)
    # get a drawing
    dwg = svgwrite.Drawing(filename, profile='tiny',
    size = (cols*cellSize+2*padding,rows*cellSize+2*padding))
    # define the colormap, in this case grayscale since black and white
    colorScale = lambda val: svgwrite.utils.rgb(int(255*(val-minVal)/(maxVal-minVal)),
    int(255*(val-minVal)/(maxVal-minVal)),
    int(255*(val-minVal)/(maxVal-minVal)))
    # get the color of each pixel in the matrix and draw it
    for i in range(rows):
    for j in range(cols):
    color = colorScale(matrix[i, j])
    dwg.add(dwg.rect(insert=(j * cellSize + padding, i * cellSize + padding),
    size=(cellSize, cellSize),
    fill=color))
    dwg.save() # save

    1. PIL.save(). Files too large

    The problem could be also solved by generating better shapes. This would not be an obstacle either. I am open to re-write using a different method, would be grateful if someone would just point me in the right direction.

    Continue reading...

Compartilhe esta Página