Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Convert Image to gds2 layer

joejoe
edited November 2009 in Layout
Hi!

Is it possible to convert the imported image to a gds2 layer?

Best regards,
Joe

Comments

  • edited November 2009

    Hi Joe,

    the image import feature is intended for visualization purposes, that's why no conversion to layout is provided currently.

    It is possible to write a Ruby script that extracts information from the images and creates layout from that. The method of extracting layout depends on the application you have. For example, it would be possible to extract a gray level contour as a polygon, although that's more demanding on the algorithmic side.

    What exactly are you looking for?

    Best regards,

    Matthias

  • joejoe
    edited 8:31PM
    Hi Matthias,

    I'm just looking for a nice method to convert images to gds2 in order to generate Logos for ICs. The image import feature of Klayout looks very good as it is possible to define the pixel size in microns. This is important because the logos shouldn't violate certain design rules.
    The only thing which I need in addition is to extract 2 or 3 different colours as polygons or rectangles.


    Best regards,
    Joe
  • edited December 2009

    Hi Joe,

    I prepared a sample script that demonstrates how to convert an image to layout.
    To install the script, copy the code below to a file with a suffix .rbm, i.e. "image2gds.rbm" into
    the installation directory (that is where the klayout executable is).

    This script will create a new menu entry in the "Tools" menu: "Image channes to layers".

    The function will take the pixel data of all images loaded and convert each pixel into a rectangle in
    predefined layers, one per color channel. Each pixel is converted into a rectangle when the respective color value in that
    channel is above 50%. Three layers can be specified whose layer and datatype are hard coded in
    the "gds2_layers" array around line 17. Currently, layers 1, 2 and 3 are used for red, green and blue
    channels respectively. Datatype is 0.

    The script should be regarded as an example. I hope I added enough comments to enable you to adjust
    the script to your needs.

    Best regards,

    Matthias

    class MenuAction < RBA::Action
      def initialize( title, shortcut, &action ) 
        self.title = title
        self.shortcut = shortcut
        @action = action
      end
      def triggered 
        @action.call( self ) 
      end
    private
      @action
    end
    
    $image2gds_handler = MenuAction.new( "Image channels to layers", "" ) do 
    
      # Defines the GDS2 layers where the three channels go.
      gds2_layers = [
        RBA::LayerInfo.new( 1, 0 ),  # Red channel (layer, datatype)
        RBA::LayerInfo.new( 2, 0 ),  # Green channe (layer, datatype)
        RBA::LayerInfo.new( 3, 0 ),  # Blue channe (layer, datatype)
      ]
    
      app = RBA::Application.instance
      mw = app.main_window
    
      lv = mw.current_view
      if lv == nil
        raise "No view selected"
      end
    
      cv = lv.active_cellview
      if !cv.is_valid?
        raise "No cell or no layout found"
      end
    
      # Create the layers if they do not exist already.
      # Prepare a vector (layers) which contains the layer indices for the relevant layers.
      layers = []
    
      gds2_layers.each do |l|
    
        layer=-1
    
        cv.layout.layer_indices.each do |li|
          if cv.layout.get_info(li).is_equivalent?(l)
            layer = li
            break
          end
        end
    
        if layer<0
    
          # layer does not exist yet: create a new layer (both in the layout and the layer list)
    
          layer = cv.layout.insert_layer(l)
    
          lp = RBA::LayerPropertiesNode.new
          lp.source_layer = l.layer
          lp.source_datatype = l.datatype
          lv.init_layer_properties(lp)
          lv.insert_layer(lv.end_layers, lp)
    
        end 
    
        layers.push(layer)
    
      end
    
      # This call is important to keep the layer list consistent when 
      # layers have been added or removed:
      lv.update_content
    
      # Prepare an array of all images in the view
      images = []
      lv.each_image { |i| images.push(i) }
    
      # The database unit
      dbu = cv.layout.dbu
    
      if images.size > 0
    
        # start transaction for "undo"
        lv.transaction( "Image channels to RGB" )
    
        # iterate over all images
        images.each do |image|
    
          # This transformation will transform a pixel to the target location of the pixel in the layout 
          trans = RBA::ICplxTrans.from_dtrans(RBA::DCplxTrans.new(1 / dbu) * image.trans * RBA::DCplxTrans.new(dbu))
    
          # The dimension of one pixel 
          pw = image.pixel_width / dbu
          ph = image.pixel_height / dbu
    
          # iterate over all channels
          (0..(layers.size-1)).each do |c|
    
            # That is where the shapes go
            shapes = cv.cell.shapes(layers [c])
    
            # Iterate over all rows
            (0..(image.height-1)).each do |y|
    
              # Iterate over all columns
              (0..(image.width-1)).each do |x|
    
                # Use each channel for a different layer
                # d>0.5 selects all pixels with a level >50% in that channel
                d = image.get_pixel(x, y, c)
                if d>0.5
    
                  # Create a polygon corresponding to one pixel
                  p1 = RBA::DPoint.new(x * pw, y * ph)
                  p2 = RBA::DPoint.new((x + 1) * pw, (y + 1) * ph)
                  dbox = RBA::DBox.new(p1, p2)
                  box = RBA::Box.from_dbox(dbox)
                  poly = RBA::Polygon.new(box)
                  shapes.insert(poly.transformed_cplx(trans))
    
                end
    
              end
    
            end
    
          end
    
        end
    
        # commit transaction
        lv.commit
    
      end
    
    end
    
    app = RBA::Application.instance
    mw = app.main_window
    
    menu = mw.menu
    menu.insert_separator("tools_menu.end", "name")
    menu.insert_item("tools_menu.end", "image2gds", $image2gds_handler)
    
  • JayJay
    edited 8:31PM
    My experience ...

    Putting the .rbm script in the same location as klayout binary doesn't work. If I put it in the current working directory, it works.
  • joejoe
    edited December 2009
    Hi Matthias,

    many thanks for your script.

    It works pretty fine and it is exactly what I was looking for!

    Might be a good idea to include a similar function in a new release of KLayout.

    @Jay: It works also in the directory where the KLayout binary is (I'm using the windows version of KLayout at the moment).

    Best regards,
    Joe
  • edited 8:31PM

    Hi,

    I hope that script serves as a preliminary solution.

    @Jay: the problem with the .rbm files may be connected with the shell or system you are using. I am also not able to reproduce it on Ubuntu and Windows. However I am interested in feedback from other platforms.

    Best regards,

    Matthias

  • edited 8:31PM
    Hi,

    I am using klayout on CentOS 4.7 and if I put the .rbm script in the directory where I start klayout, it works but putting the .rbm script in the same location as klayout binary doesn't work.
    I tried to set also RUBYLIB and RUBYPATH w/ the directory containing .rbm files but no changes, seem not to be used.

    Best Regards,
    Joaquim
  • edited 8:31PM

    Hi Joaquim,

    KLayout derives the installation path form the $0 argument. I learned that shells behave differently and for some shells the absolute path cannot be derived from that argument.

    Currently, one workaround is to start KLayout with the full path, i.e.

    /use/bin/klayout ... 
    

    Maybe you can set an alias for this command, so it's less effort typing.

    For the next release I plan to add a more consistent ruby module installation scheme which should avoid those problems.

    Best regards,

    Matthias

  • edited 8:31PM

    Hi Joaquim,

    in the lastest version 0.19.3 you can set an environment variable $KLAYOUT_PATH which points to the directory containing the .rbm files.

    Best regards,

    Matthias

  • edited 8:31PM
    Hi Matthias,

    it works fine. Thanks.

    Best Regards,
    Joaquim
  • edited 8:31PM
    For this routine, I do not see how to load the image, for instance example.bmp
    Please, can you give more details on its usage ?

    Thanks,
    OkGuy
  • edited 8:31PM

    Hi,

    the idea is to first add an image with "Edit/Add Image", adjust the position and size and then let the script convert that image (or the images) to GDS geometry.

    Is that what you are looking for?

    Matthias

  • edited 8:31PM
    Hi,

    I'm interesed in converting an image to a polygon, by extracting the gray level as commented above.

    Some one to help me?

    Thanks
  • edited 8:31PM

    Hi,

    there are numerous vectorizers out on the net. If you need a CAD format, you can try online image to DXF translators (google for "image to dxf converter online").

    Matthias

  • edited 8:31PM
    Thank you, Matthias. Finally, I have modified the script you attached above, and it works fine :)
  • edited 8:31PM
    Hello @MarryM,

    can you please past your code that you have modified .

    Thank you
  • edited September 2015
    Hi @Matthias,

    Your script to import an image to gds looks very good! However, do I need to add this script to the source file, and compile klayout myself? I installed the binary version on my mac pro. Could you possible to run it with the binary version?

    Thank you
  • edited 8:31PM

    Hello,

    no, no need to recompile. You'll find a lot of documentation about using and writing scripts here: http://www.klayout.de/doc/programming/index.html.

    Matthias

  • edited October 2015
    The best way I've found is to convert a raster image (eg. PNG, JPG) into vector (PDF) and then into DXF. I found InkScape was the best tool for this - although on MacOS you also have to install XQuartz (an X-windows system) to use it.

    To convert your raster image into PDF, I use PoTrace (a command-line tool that is also built into InkScape), or just do it through InkScape itself.
    Like this tutorial: http://www.wikihow.com/Convert-Raster-to-Vector
    -- see the 2nd "inkscape" method
    POTrace (command-line tool): http://potrace.sourceforge.net

    Then convert the PDF into DXF - InkScape can also save into DXF (Autocad R14 compatible). I was then able to open this in KLayout (or AutoCad)! Of course, then you can save it as GDSii or any other format KLayout supports.
  • Hi all,

    I've create a Python Macro script to convert image to Oasis file, along with a simple GUI. You may take a look if interested. https://github.com/zwh42/KLayout_tools/blob/master/image_to_oasis_file/image_to_oasis.py

    Thanks

  • Thanks a lot for sharing this! :-)

    Matthias

Sign In or Register to comment.