-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* test images from blender * add line * fmt
- Loading branch information
1 parent
2883b45
commit fcd52b4
Showing
17 changed files
with
289 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .spec import Camera # noqa: F401 |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class Camera: | ||
def __init__(self, focal_length: float, sensor_width: float) -> None: | ||
self.focal_length = focal_length | ||
self.sensor_width = sensor_width |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from cnceye.cmm.cmm import Cmm # noqa: F401 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from cnceye.coordinates import Coordinates | ||
from cnceye.camera import Camera | ||
from .pixel import get_field_of_view, get_pixel_per_mm | ||
|
||
|
||
class Cmm: | ||
def __init__(self, image, center_coordinates: Coordinates, camera: Camera) -> None: | ||
self.image = image | ||
self.center = center_coordinates | ||
self.camera = camera | ||
|
||
def get_opencv_origin(self, image, distance: float) -> Coordinates: | ||
# opencv origin is at top left corner | ||
pixel_per_mm = self.pixel_per_mm(distance) | ||
diff_in_pixel = (-image.shape[1] / 2, image.shape[0] / 2, 0) | ||
diff_in_mm = tuple(x / pixel_per_mm for x in diff_in_pixel) | ||
return Coordinates(tuple(map(sum, zip(self.center, diff_in_mm)))) | ||
|
||
def pixel_per_mm(self, distance: float) -> float: | ||
field_of_view = get_field_of_view( | ||
self.camera.focal_length, self.camera.sensor_width, distance | ||
) | ||
return get_pixel_per_mm(field_of_view, self.image.shape[1]) | ||
|
||
def from_opencv_coord(self, distance: float, opencv_xy: tuple) -> Coordinates: | ||
pixel_per_mm = self.pixel_per_mm(distance) | ||
opencv_origin = self.get_opencv_origin(self.image, distance) | ||
return Coordinates( | ||
( | ||
opencv_origin.x + opencv_xy[0] / pixel_per_mm, | ||
opencv_origin.y - opencv_xy[1] / pixel_per_mm, | ||
self.center.x - distance, | ||
) | ||
) | ||
|
||
def from_pixel_length(self, distance: float, pixel_length) -> float: | ||
pixel_per_mm = self.pixel_per_mm(distance) | ||
return pixel_length / pixel_per_mm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
def get_field_of_view(focal_length: float, sensor_width: float, distance: float): | ||
return sensor_width / focal_length * distance | ||
|
||
|
||
def get_pixel_per_mm(field_of_view: float, pixel_width: int): | ||
return pixel_width / field_of_view |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from cnceye.coordinates.coord import Coordinates # noqa: F401 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from typing import Tuple | ||
|
||
|
||
class Coordinates(Tuple): | ||
def __init__(self, xyz: Tuple[float]) -> None: | ||
super().__init__() | ||
self.x = xyz[0] | ||
self.y = xyz[1] | ||
self.z = xyz[2] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import cv2 | ||
import numpy as np | ||
|
||
|
||
def get_lines( | ||
image, | ||
gaussian_blur_size=5, | ||
canny_low_threshold=100, | ||
canny_high_threshold=200, | ||
rho=0.1, | ||
hough_threshold=50, | ||
min_line_length=50, | ||
max_line_gap=200, | ||
): | ||
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | ||
blur_gray = cv2.GaussianBlur(gray, (gaussian_blur_size, gaussian_blur_size), 0) | ||
edges = cv2.Canny( | ||
blur_gray, | ||
canny_low_threshold, | ||
canny_high_threshold, | ||
apertureSize=3, | ||
L2gradient=True, | ||
) | ||
edges = cv2.dilate(edges, None, iterations=1) | ||
edges = cv2.erode(edges, None, iterations=1) | ||
|
||
lines = cv2.HoughLinesP( | ||
edges, | ||
rho, | ||
np.pi / 180 * rho, | ||
hough_threshold, | ||
minLineLength=min_line_length, | ||
maxLineGap=max_line_gap, | ||
) | ||
return lines |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import bpy | ||
import os | ||
|
||
|
||
def render_image(output_path, camera_position, camera_rotation, light_position): | ||
# Set camera position and rotation | ||
camera = bpy.data.objects["Camera"] | ||
camera.location = camera_position | ||
camera.rotation_euler = camera_rotation | ||
|
||
# Set light position | ||
lamp = bpy.data.objects["Light"] | ||
lamp.location = light_position | ||
|
||
# Set rendering settings | ||
bpy.context.scene.render.image_settings.file_format = "PNG" | ||
bpy.context.scene.render.filepath = output_path | ||
|
||
# Render the image | ||
bpy.ops.render.render(write_still=True) | ||
|
||
|
||
# Example usage | ||
if __name__ == "__main__": | ||
# Define camera and light positions | ||
camera_position_start = (-0.05, 0.025, 0.06) | ||
camera_rotation = (0.0, 0.0, 0.0) | ||
light_position = (0, 0, 0.1) | ||
|
||
# Create a folder to save the rendered images | ||
output_folder = "/path/to/output_images" | ||
os.makedirs(output_folder, exist_ok=True) | ||
|
||
# Render images with different camera and light positions | ||
for i in range(10): | ||
camera_position = ( | ||
camera_position_start[0] + i * 0.1, | ||
camera_position_start[1], | ||
camera_position_start[2], | ||
) | ||
output_path = os.path.join(output_folder, f"image_{i + 1}.png") | ||
render_image(output_path, camera_position, camera_rotation, light_position) | ||
|
||
print("Rendering completed!") |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
import cv2 | ||
from cnceye import camera | ||
from cnceye.camera import calib | ||
|
||
|
||
def test_undistort_img(): | ||
image = cv2.imread("tests/fixtures/images/coins.jpg") | ||
camera_data_path = "tests/fixtures/camera/google-pixel5-5g.json" | ||
_undistorted_image = camera.undistort_img(image, camera_data_path) | ||
_undistorted_image = calib.undistort_img(image, camera_data_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import cv2 | ||
from cnceye.cmm import Cmm | ||
from cnceye.camera import Camera | ||
from cnceye.coordinates import Coordinates | ||
from cnceye.circle import get_circles | ||
from cnceye.line import get_lines | ||
|
||
focal_length = 50.0 # mm | ||
camera_height = 60.0 # mm | ||
object_height = 10.0 # mm | ||
distance = camera_height - object_height | ||
sensor_width = 36.0 # mm | ||
camera = Camera(focal_length, sensor_width) | ||
|
||
|
||
def diff_in_micron(expected, actual): | ||
return (expected - actual) * 1000 | ||
|
||
|
||
def test_opencv_coord_1(): | ||
image = cv2.imread("tests/fixtures/output_images/image_1.png") | ||
center_coordinates = Coordinates((-50.0, 25.0, 60.0)) | ||
|
||
cmm = Cmm(image, center_coordinates, camera) | ||
circles = get_circles(image, param2=30) | ||
(x_pixel, y_pixel, r_pixel) = circles[0][0] | ||
|
||
# check radius is close to expected radius | ||
expected_radius = 3.0 # mm | ||
radius_from_img_in_mm = cmm.from_pixel_length(distance, r_pixel) | ||
radius_diff_in_micron = diff_in_micron(expected_radius, radius_from_img_in_mm) | ||
print(f"radius: {radius_diff_in_micron:.2f} μm") | ||
assert radius_diff_in_micron < 100.0 | ||
|
||
# check center is close to expected center | ||
expected_circle_center = Coordinates((-48.0, 23.0, 10.0)) | ||
circle_center_from_img_in_mm = cmm.from_opencv_coord(distance, (x_pixel, y_pixel)) | ||
x_from_img_in_mm = circle_center_from_img_in_mm.x | ||
y_from_img_in_mm = circle_center_from_img_in_mm.y | ||
|
||
x_diff_in_micro = diff_in_micron(expected_circle_center.x, x_from_img_in_mm) | ||
print(f"x: {x_diff_in_micro:.2f} μm") | ||
assert x_diff_in_micro < 100.0 | ||
|
||
y_diff_in_micron = diff_in_micron(expected_circle_center.y, y_from_img_in_mm) | ||
print(f"y: {y_diff_in_micron:.2f} μm") | ||
assert y_diff_in_micron < 100.0 | ||
|
||
lines = get_lines(image) | ||
assert len(lines) > 0 | ||
expected_corner = Coordinates((-53.0, 28.0, 10.0)) | ||
x_pixel, y_pixel = lines[0][0][0], lines[0][0][1] | ||
corner_from_img_in_mm = cmm.from_opencv_coord(distance, (x_pixel, y_pixel)) | ||
x_from_img_in_mm = corner_from_img_in_mm.x | ||
y_from_img_in_mm = corner_from_img_in_mm.y | ||
|
||
x_diff_in_micro = diff_in_micron(expected_corner.x, x_from_img_in_mm) | ||
print(f"x: {x_diff_in_micro:.2f} μm") | ||
assert x_diff_in_micro < 100.0 | ||
|
||
y_diff_in_micron = diff_in_micron(expected_corner.y, y_from_img_in_mm) | ||
print(f"y: {y_diff_in_micron:.2f} μm") | ||
assert y_diff_in_micron < 100.0 | ||
|
||
|
||
def test_opencv_coord_2(): | ||
image = cv2.imread("tests/fixtures/output_images/image_2.png") | ||
center_coordinates = Coordinates((-40.0, 25.0, 60.0)) | ||
|
||
cmm = Cmm(image, center_coordinates, camera) | ||
circles = get_circles(image, param2=30) | ||
(x_pixel, y_pixel, r_pixel) = circles[0][0] | ||
|
||
# check radius is close to expected radius | ||
expected_radius = 3.0 # mm | ||
radius_from_img_in_mm = cmm.from_pixel_length(distance, r_pixel) | ||
radius_diff_in_micron = diff_in_micron(expected_radius, radius_from_img_in_mm) | ||
print(f"radius: {radius_diff_in_micron:.2f} μm") | ||
assert radius_diff_in_micron < 100.0 | ||
|
||
# check center is close to expected center | ||
expected_circle_center = Coordinates((-48.0, 23.0, 10.0)) | ||
circle_center_from_img_in_mm = cmm.from_opencv_coord(distance, (x_pixel, y_pixel)) | ||
x_from_img_in_mm = circle_center_from_img_in_mm.x | ||
y_from_img_in_mm = circle_center_from_img_in_mm.y | ||
|
||
x_diff_in_micro = diff_in_micron(expected_circle_center.x, x_from_img_in_mm) | ||
print(f"x: {x_diff_in_micro:.2f} μm") | ||
assert x_diff_in_micro < 100.0 | ||
|
||
y_diff_in_micron = diff_in_micron(expected_circle_center.y, y_from_img_in_mm) | ||
print(f"y: {y_diff_in_micron:.2f} μm") | ||
assert y_diff_in_micron < 100.0 | ||
|
||
lines = get_lines(image) | ||
assert len(lines) > 0 | ||
expected_corner = Coordinates((-53.0, 28.0, 10.0)) | ||
x_pixel, y_pixel = lines[0][0][0], lines[0][0][1] | ||
corner_from_img_in_mm = cmm.from_opencv_coord(distance, (x_pixel, y_pixel)) | ||
x_from_img_in_mm = corner_from_img_in_mm.x | ||
y_from_img_in_mm = corner_from_img_in_mm.y | ||
|
||
x_diff_in_micro = diff_in_micron(expected_corner.x, x_from_img_in_mm) | ||
print(f"x: {x_diff_in_micro:.2f} μm") | ||
assert x_diff_in_micro < 100.0 | ||
|
||
y_diff_in_micron = diff_in_micron(expected_corner.y, y_from_img_in_mm) | ||
print(f"y: {y_diff_in_micron:.2f} μm") | ||
assert y_diff_in_micron < 100.0 | ||
|
||
|
||
def test_opencv_coord_3(): | ||
image = cv2.imread("tests/fixtures/output_images/image_3.png") | ||
center_coordinates = Coordinates((-30.0, 25.0, 60.0)) | ||
|
||
cmm = Cmm(image, center_coordinates, camera) | ||
circles = get_circles(image, param2=30) | ||
(x_pixel, y_pixel, r_pixel) = circles[0][0] | ||
|
||
# check radius is close to expected radius | ||
expected_radius = 3.0 # mm | ||
radius_from_img_in_mm = cmm.from_pixel_length(distance, r_pixel) | ||
radius_diff_in_micron = diff_in_micron(expected_radius, radius_from_img_in_mm) | ||
print(f"radius: {radius_diff_in_micron:.2f} μm") | ||
# assert radius_diff_in_micron < 100.0 | ||
|
||
# check center is close to expected center | ||
expected_circle_center = Coordinates((-48.0, 23.0, 10.0)) | ||
circle_center_from_img_in_mm = cmm.from_opencv_coord(distance, (x_pixel, y_pixel)) | ||
x_from_img_in_mm = circle_center_from_img_in_mm.x | ||
y_from_img_in_mm = circle_center_from_img_in_mm.y | ||
|
||
x_diff_in_micro = diff_in_micron(expected_circle_center.x, x_from_img_in_mm) | ||
print(f"x: {x_diff_in_micro:.2f} μm") | ||
# assert x_diff_in_micro < 100.0 | ||
|
||
y_diff_in_micron = diff_in_micron(expected_circle_center.y, y_from_img_in_mm) | ||
print(f"y: {y_diff_in_micron:.2f} μm") | ||
# assert y_diff_in_micron < 100.0 | ||
|
||
lines = get_lines(image) | ||
assert len(lines) > 0 |