rasterize() to output 408.24 µm field as 1080BMP, 0.378 µm line became 2 pixels instead of 1 pixel

I used the rasterize() function to convert GDS to BMP. My goal is to split the GDS image into fields of 408.24 [um], with the output image being 1080x1080, and achieving a resolution of 0.378 microns per pixel.
However... almost all areas (except for two specific points I marked) became two pixels wide instead of the one-pixel width I set. I’m currently working on finding the cause of this issue.
Heres is my python ,GDS and Bmp Output.

Comments

  • Still think this is rounding error residue / "DBU beat frequency" stacking up.

    Does your source data have such a funky DBU initially?

    If so then maybe you must first upscale DBU per distance to a least-common-multiple, rasterize that, and then downscale (basic image resize) to the target pixel scale and count.

    Now all I know about changing DBU on the fly is, "better left alone if you don't know what you're doing" so I don't. But I think this is what you need for harmonizing source and product per goal.
  • edited January 11

    Hi @Flyingmyd,

    @dick_freebird is right - the layout is not aligned with the grid you're using.

    Let me demonstrate what happens by using grayscale values:

            rgb = int(math.floor(a * 255.0 / (pixel_size_dbu.x * pixel_size_dbu.y) + 0.5)) * 0x10101
    

    For example this line:

    Comes out as a two-pixel grayscale line:

    The reason is that with this rasterization:

    2025-01-11 18:33:44,840 - DEBUG - box_to_render_dbu: (0,0;408240,408240)
    2025-01-11 18:33:44,840 - DEBUG - pixel_size_dbu: 378,378
    

    and these coordinates of the line rectangle:

    ![](https://www.klayout.de/forum/uploads/editor/4r/g7jih72v5v03.png "")
    

    the line is on the 0.378 µm grid vertically as 102.06 and 204.12 are integer multiples of 0.378, but not horizontally: 103.742 and 104.12 are not integer multiples of 0.378. In other words, the line sits between two pixels and overlaps both of them. Hence, the area covered by the line is divided between the left and right pixel column.

    In your code you set the color to white when the area is not null - this means the non-zero area contributions of the line make it 2 pixels wide.

    The layout has to fit precisely on the rasterization grid to render exactly 0 or non-zero area values.

    Matthias

  • @dick_freebird
    @Matthias
    Finally, I achieved a resolution of 0.378 µm per pixel! The method was to align the points of the primitives (either boxes or polygons) to the nearest multiple of 0.378.

    The advantage of this approach is that it truly achieves 0.378 µm per pixel. The downside is that it introduces some degree of displacement and deformation to the shapes. However, considering the actual purpose of the image—exposing the DMD's 1080x1080 micromirrors—the displacement and deformation are both within 0.378/2 µm. So, this method is nearly perfect.

    Thank you so much!! You've helped me solve a major challenge at work!

  • Very good! :)

    But actually, when you map a layout to a pixel array without semi-filled pixels, you do introduce some layout distortion. That is inevitable. Either you accept to have a line overlapping pixels or you need to have perfectly aligned layout polygons.

    Just out of curiosity: is 0.378 the actual size of the pixels or already downscaled by some projection optics? In order words: with 4x projection optics for example, would you be able to achieve a 94.5nm resolution?

    Thanks,

    Matthias

  • @Matthias
    Hello,Matthias. :)
    When I rasterize a DXF graphic, if the DPI is 0.378, each point of the graphic is aligned to multiples of 0.378 microns (this operation is handled outside the script), and the layout is rasterized according to this standard. If the length of a region is a multiple of 0.378, the number of pixels it occupies will be that multiple. For example, if the length of a region is 3 times 0.378, it will occupy 3 pixels.

    However, when the DPI is 0.1512, each coordinate of the graphic is aligned to multiples of 0.1512 microns for rasterization. In this case, the rasterized graphic may occupy one extra pixel and fail to match perfectly. The BMP size is always 1080 pixels by 1080 pixels. Why does this happen?

  • Pixels are inherently integer and therefore are going to end up toggling around rounding error.

    Grain of sand or no grain of sand. Dust is with the wind.
  • edited March 23
Sign In or Register to comment.