Spaces:
Runtime error
Runtime error
Upload 2 files
Browse files- Image_height.py +74 -0
- Image_stitching.py +94 -0
Image_height.py
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from plantcv import plantcv as pcv
|
2 |
+
from PIL import Image
|
3 |
+
import glob
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
import os
|
6 |
+
import numpy as np
|
7 |
+
import pandas as pd
|
8 |
+
from sklearn.decomposition import PCA
|
9 |
+
from skimage.filters import threshold_li
|
10 |
+
|
11 |
+
|
12 |
+
class options:
|
13 |
+
def __init__(self, image_path):
|
14 |
+
self.image = image_path
|
15 |
+
self.debug = "plot"
|
16 |
+
self.tmp_dir = "plantpattern"
|
17 |
+
self.result = os.path.join(self.tmp_dir, "try2.txt")
|
18 |
+
self.writeimg = False
|
19 |
+
self.outdir = "plantpattern"
|
20 |
+
os.makedirs(self.tmp_dir, exist_ok=True)
|
21 |
+
|
22 |
+
def image_height(image_path, camera_distance):
|
23 |
+
# Get options
|
24 |
+
args = options(image_path)
|
25 |
+
|
26 |
+
# Set debug to the global parameter
|
27 |
+
pcv.params.debug = args.debug
|
28 |
+
|
29 |
+
# Read image
|
30 |
+
|
31 |
+
# Inputs:
|
32 |
+
# filename - Image file to be read in
|
33 |
+
# mode - How to read in the image; either 'native' (default), 'rgb', 'gray', or 'csv'
|
34 |
+
original_img, path, filename = pcv.readimage(filename=args.image)
|
35 |
+
|
36 |
+
gray = pcv.rgb2gray(rgb_img=original_img)
|
37 |
+
thresh = threshold_li(gray)
|
38 |
+
binary = gray > thresh
|
39 |
+
|
40 |
+
s_thresh = binary.astype(int)
|
41 |
+
bs = pcv.logical_or(bin_img1=gray, bin_img2=np.uint8(s_thresh*255))
|
42 |
+
masked = pcv.apply_mask(img=original_img, mask=bs, mask_color='black')
|
43 |
+
ab_fill = pcv.fill(bin_img=s_thresh, size=10)
|
44 |
+
masked2 = pcv.apply_mask(img=masked, mask=ab_fill, mask_color='black')
|
45 |
+
id_objects, obj_hierarchy = pcv.find_objects(img=np.uint8(original_img*255), mask=ab_fill)
|
46 |
+
roi1, roi_hierarchy= pcv.roi.rectangle(img=masked2, x=95, y=5, h=500, w=350)
|
47 |
+
roi_objects, hierarchy3, kept_mask, obj_area = pcv.roi_objects(img=original_img, roi_contour=roi1,
|
48 |
+
roi_hierarchy=roi_hierarchy,
|
49 |
+
object_contour=id_objects,
|
50 |
+
obj_hierarchy=obj_hierarchy,
|
51 |
+
roi_type='partial')
|
52 |
+
|
53 |
+
obj, mask = pcv.object_composition(img=original_img, contours=roi_objects, hierarchy=hierarchy3)
|
54 |
+
analysis_image = pcv.analyze_object(img=original_img, obj=obj, mask=mask, label="default")
|
55 |
+
boundary_image2 = pcv.analyze_bound_horizontal(img=np.uint8(original_img*255), obj=obj, mask=mask,
|
56 |
+
line_position=510, label="default")
|
57 |
+
height_above_reference = pcv.outputs.observations['default']['height_above_reference']['value']
|
58 |
+
#small greenhouse distance = 30cm
|
59 |
+
#56.3 * 56.3
|
60 |
+
image_width, image_height, h = original_img.shape
|
61 |
+
x_offset = 56.3/512
|
62 |
+
actual_greenhouse_height = x_offset * height_above_reference
|
63 |
+
# print("Actual Height of plant:", actual_greenhouse_height)
|
64 |
+
# Create a DataFrame with the actual height
|
65 |
+
data = {'Parameter': ['Height Above Reference (pixels)', 'Plant height (cm)', 'Image Width (pixels)', 'Pixel Size (cm)'],
|
66 |
+
'Value': [height_above_reference, actual_greenhouse_height, image_width, x_offset]}
|
67 |
+
df = pd.DataFrame(data)
|
68 |
+
|
69 |
+
return df, actual_greenhouse_height
|
70 |
+
|
71 |
+
|
72 |
+
|
73 |
+
|
74 |
+
|
Image_stitching.py
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
import matplotlib.pyplot as plt
|
4 |
+
import pdb
|
5 |
+
|
6 |
+
def rotate_to_horizontal(image):
|
7 |
+
# Rotate the image to horizontal (90 degrees counterclockwise)
|
8 |
+
rotated_image = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE)
|
9 |
+
return rotated_image
|
10 |
+
|
11 |
+
def rotate_to_vertical(image):
|
12 |
+
# Rotate the image back to vertical (90 degrees clockwise)
|
13 |
+
rotated_image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)
|
14 |
+
return rotated_image
|
15 |
+
|
16 |
+
def plot_images(images):
|
17 |
+
num_images = len(images)
|
18 |
+
|
19 |
+
for i, image in enumerate(images):
|
20 |
+
plt.figure(figsize=(6, 6))
|
21 |
+
plt.imshow(image)
|
22 |
+
plt.title(f"Image {i+1}/{num_images}")
|
23 |
+
plt.axis('off')
|
24 |
+
plt.show()
|
25 |
+
|
26 |
+
def image_stitching(images):
|
27 |
+
# images = [cv2.imread(path) for path in image_paths]
|
28 |
+
|
29 |
+
images = [image.astype(np.uint8) for image in images]
|
30 |
+
images = [rotate_to_horizontal(image) for image in images]
|
31 |
+
images = list(reversed(images))
|
32 |
+
if len(images) == 15:
|
33 |
+
images = images[2:12]
|
34 |
+
#plot_images(images)
|
35 |
+
|
36 |
+
# Create a list to store the stitched images
|
37 |
+
stitched_images = []
|
38 |
+
|
39 |
+
# Accumulated homography matrix for stitching
|
40 |
+
accumulated_homography = np.eye(3)
|
41 |
+
|
42 |
+
# Iterate through pairs of adjacent images and stitch them together
|
43 |
+
for i in range(len(images) - 1):
|
44 |
+
# Perform keypoint and feature descriptor extraction
|
45 |
+
orb = cv2.ORB_create()
|
46 |
+
keypoints_and_descriptors = [orb.detectAndCompute(image, None) for image in [images[i], images[i + 1]]]
|
47 |
+
|
48 |
+
# Match the keypoints using Brute-Force Matcher
|
49 |
+
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
|
50 |
+
matches = bf.match(keypoints_and_descriptors[0][1], keypoints_and_descriptors[1][1])
|
51 |
+
|
52 |
+
# Filter the matches to remove outliers using RANSAC
|
53 |
+
src_pts = np.float32([keypoints_and_descriptors[0][0][m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
|
54 |
+
dst_pts = np.float32([keypoints_and_descriptors[1][0][m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)
|
55 |
+
|
56 |
+
M, _ = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
|
57 |
+
|
58 |
+
# Accumulate the homography matrices
|
59 |
+
accumulated_homography = np.dot(M, accumulated_homography)
|
60 |
+
|
61 |
+
# Warp perspective and stitch the images
|
62 |
+
stitched_image = cv2.warpPerspective(images[i + 1], accumulated_homography,
|
63 |
+
(images[i].shape[1] + images[i + 1].shape[1], images[i].shape[0]))
|
64 |
+
stitched_image[0:images[i].shape[0], 0:images[i].shape[1]] = images[i]
|
65 |
+
|
66 |
+
# Remove the empty pixels and retain maximum image information
|
67 |
+
# stitched_image = remove_empty_pixels(stitched_image)
|
68 |
+
|
69 |
+
stitched_images.append(stitched_image)
|
70 |
+
|
71 |
+
# Combine all stitched images into a final panorama
|
72 |
+
final_panorama = stitched_images[0]
|
73 |
+
for i in range(1, len(stitched_images)):
|
74 |
+
final_panorama = cv2.warpPerspective(stitched_images[i], np.eye(3),
|
75 |
+
(final_panorama.shape[1] + stitched_images[i].shape[1], final_panorama.shape[0]))
|
76 |
+
final_panorama[0:stitched_images[i].shape[0], 0:stitched_images[i].shape[1]] = stitched_images[i]
|
77 |
+
|
78 |
+
gray_images = [cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) for image in images[:2]]
|
79 |
+
|
80 |
+
# Draw the keypoints on the images
|
81 |
+
keypoints_drawn = [cv2.drawKeypoints(gray_image, kp[0], None, color=(0, 255, 0),
|
82 |
+
flags=cv2.DrawMatchesFlags_DRAW_RICH_KEYPOINTS) for gray_image, kp in
|
83 |
+
zip(gray_images, keypoints_and_descriptors[:2])]
|
84 |
+
|
85 |
+
# Draw the matches on the images
|
86 |
+
matches_drawn = cv2.drawMatches(images[0], keypoints_and_descriptors[0][0], images[1],
|
87 |
+
keypoints_and_descriptors[1][0], matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
|
88 |
+
|
89 |
+
# Crop the final image to 512x512 centered around the middle
|
90 |
+
cropped_final_panorama = final_panorama[:512, :512]
|
91 |
+
rotated_final_panorama = rotate_to_vertical(cropped_final_panorama)
|
92 |
+
|
93 |
+
|
94 |
+
return rotated_final_panorama
|