How to use the rasterize function to render a specified area of a GDS file?

assuming a pixel physical size of 20x20 nm, and how to achieve high-precision rendering?

Comments

  • edited December 1

    Here is some code. I hope the comments are self-explaining:


    # Illustration of how to use Region.rasterize # This code takes the shapes from layer 66/20 # of the current cell and rasterizes a region # 0,1 .. 80,210 (µm) with a resultion of 100nm cell = pya.CellView.active().cell ly = cell.layout() layer = ly.layer(66, 20) # box to render in µm box_to_render = pya.DBox(0, 10, 80, 210) # pixel size in µm pixel_size = pya.DVector(0.1, 0.1) # creates a Region object with the shapes to render # using "box_to_render" to confine the search for shapes shapes_to_render = pya.Region(cell.begin_shapes_rec_touching(layer, box_to_render)) # Performs the rasterization # The result will be a 2d array in "areas" # where the value is the covered area per pixel # in square database units. um_to_dbu = pya.DCplxTrans(ly.dbu).inverted() box_to_render_dbu = um_to_dbu * box_to_render pixel_size_dbu = um_to_dbu * pixel_size nx = round(box_to_render_dbu.width() / pixel_size_dbu.x) ny = round(box_to_render_dbu.height() / pixel_size_dbu.y) # gives the areas covered in units of square data base units # (see comments below about "merged") areas = shapes_to_render.merged().rasterize(box_to_render_dbu.p1, pixel_size_dbu, nx, ny) # for illustration, write as grayscale image pixels = pya.PixelBuffer(len(areas[0]), len(areas)) amax = float(pixel_size_dbu.x * pixel_size_dbu.y) y = len(areas) for arow in areas: x = 0 y -= 1 for a in arow: value = int(round(255.0 * a / amax)) rgb = value * 0x10101 pixels.set_pixel(x, y, rgb) x += 1 pixels.write_png("/tmp/discussion_2630.png")

    A small test case of mine rendered a 800x2000 pixel image in less than a second:

    There is a caveat: the rasterize function will count overlapping shapes twice, hence the area may be larger than the maximum expected area. The "merged()" method will take care of that, by computing the merged polygons which are free of overlaps. If you pick a too complex region, for example a SRAM block, this method may need a lot of memory.

    If the box to render is small, there is little overhead however.

  • Thank you very much for your reply, I really appreciate it. If I need to render multiple layers, how can I do that? Perhaps the rasterized result can be converted to a grayscale image using the following code?

    ## Create a grayscale image array
    height = len(areas)
    width = len(areas[0])
    gray_array = np.zeros((height, width), dtype=np.uint8)
    amax = float(pixel_size_dbu.x * pixel_size_dbu.y)
    
    amax = float(pixel_size_dbu.x * pixel_size_dbu.y)
    
    area_values = np.array(areas).astype(float)
    gray_array = np.clip(255.0 * area_values / amax, 0, 255).astype(np.uint8)
    
    ## Reverse Y-axis
    gray_array = np.flipud(gray_array)
    
    cv2.imwrite('output_gray_image_cv2.png', gray_array)
    
Sign In or Register to comment.