Source code for gdsfactory.read.from_np

"""Read component from a numpy.ndarray."""

from __future__ import annotations

import pathlib

import numpy as np

from gdsfactory.cell import cell
from gdsfactory.component import Component
from gdsfactory.config import PATH
from gdsfactory.geometry.boolean import boolean


def compute_area_signed(pr) -> float:
    """Return the signed area enclosed by a ring using the linear time.

    algorithm at http://www.cgafaq.info/wiki/Polygon_Area. A value >= 0
    indicates a counter-clockwise oriented ring.

    """
    xs, ys = map(list, zip(*pr))
    xs.append(xs[1])
    ys.append(ys[1])
    return sum(xs[i] * (ys[i + 1] - ys[i - 1]) for i in range(1, len(pr))) / 2.0


[docs] @cell def from_np( ndarray: np.ndarray, nm_per_pixel: int = 20, layer: tuple[int, int] = (1, 0), threshold: float = 0.99, invert: bool = True, border_pad_num_pixels: int = 2, border_pad_pixel_value: float | None = None, ) -> Component: """Returns Component from a np.ndarray. Extracts contours skimage.measure.find_contours using `threshold`. Args: ndarray: 2D ndarray representing the device layout. nm_per_pixel: scale_factor. layer: layer tuple to output gds. threshold: value along which to find contours in the array. invert: invert the mask. border_pad_num_pixels: number of pixels to pad image border with. A value of 2 is usually sufficient to capture contours along the image border. border_pad_pixel_value: set value of padding pixels (optional). This is passed to np.pad through the 'constant_values' argument. """ from skimage import measure c = Component() d = Component() pad_kwargs = {} if border_pad_pixel_value is not None: pad_kwargs = {"constant_values": border_pad_pixel_value} ndarray = np.pad(ndarray, border_pad_num_pixels, **pad_kwargs) contours = measure.find_contours(ndarray, threshold) assert len(contours) > 0, ( f"no contours found for threshold = {threshold}, maybe you can reduce the" " threshold" ) for contour in contours: area = compute_area_signed(contour) points = contour * 1e-3 * nm_per_pixel if area < 0: c.add_polygon(points, layer=layer) else: d.add_polygon(points, layer=layer) return boolean(c, d, operation="not", layer=layer) if invert else d
@cell def from_image( image_path: str | pathlib.Path = PATH.module / "samples" / "images" / "logo.png", nm_per_pixel: int = 20, layer: tuple[int, int] = (1, 0), threshold: float = 0.99, invert: bool = True, border_pad_num_pixels: int = 2, border_pad_pixel_value: float | None = None, ) -> Component: """Returns Component from a png image. Args: image_path: png file path. nm_per_pixel: scale_factor. layer: layer tuple to output gds. threshold: value along which to find contours in the array. invert: invert the mask. True by default. border_pad_num_pixels: number of pixels to pad image border with. A value of 2 is usually sufficient to capture contours along the image border. border_pad_pixel_value: set value of padding pixels (optional). This is passed to np.pad through the 'constant_values' argument. """ import matplotlib.pyplot as plt # Load the image using matplotlib img = plt.imread(image_path) if len(img.shape) == 3: img = 0.2989 * img[:, :, 0] + 0.5870 * img[:, :, 1] + 0.1140 * img[:, :, 2] # Convert image to numpy array (in fact, plt.imread already returns a numpy array) img_array = np.array(img) return from_np( img_array, nm_per_pixel=nm_per_pixel, layer=layer, threshold=threshold, invert=invert, border_pad_num_pixels=border_pad_num_pixels, border_pad_pixel_value=border_pad_pixel_value, ) if __name__ == "__main__": # import gdsfactory as gf # c1 = gf.components.straight() # c1 = gf.components.bend_circular() # c1 = gf.components.ring_single() # img = c1.to_np() # c2 = from_np(img) # c2.show() c = from_image( PATH.module / "samples" / "images" / "logo.png", nm_per_pixel=500, invert=True ) c.show()