Skip to content
This repository has been archived by the owner on Sep 5, 2023. It is now read-only.

Added GUI for saturation, brightness, hsv, and update doc for test_pf #68

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
689cf5c
control for 1 frame
Jan 29, 2023
dd8f371
controller for all frames
NLmeng Feb 4, 2023
bd90af0
real time toggle
NLmeng Feb 4, 2023
65f6e99
forcing me to save
abhigyandabla Feb 5, 2023
5d4b2a7
Merge branch 'lymeng/controller' of https://github.com/UBCAgroBot/Nav…
abhigyandabla Feb 5, 2023
555d0f0
Added brightness and saturation toggles to window
abhigyandabla Feb 5, 2023
8cc1051
real time toggle for brightness and saturation
NLmeng Feb 11, 2023
8b7377a
real time toggle for brightness and saturation
NLmeng Feb 11, 2023
fc550cd
created better GUI with tkinter
NLmeng Feb 12, 2023
54e4e36
configure to support all algorithm
NLmeng Feb 13, 2023
45bdc62
update doc, minor change to gui and pre_process
NLmeng Feb 13, 2023
42c493d
pass in filtered frame to algorithm with gui
NLmeng Feb 18, 2023
3eebc25
minor changes
NLmeng Feb 18, 2023
f8d4529
connect hsv from gui to algorithms, and added upper and lower hsv to gui
NLmeng Mar 2, 2023
7283f94
alert when UPPER hsv < LOWER hsv and vice versa
NLmeng Mar 2, 2023
f586e9d
small addition to readme
NLmeng Mar 3, 2023
e10ec73
conflicts
NLmeng Mar 3, 2023
a4a6809
autopep8
NLmeng Mar 3, 2023
3385cdd
added Pillow dependency
NLmeng Mar 3, 2023
b43fbfa
show the whole frame
NLmeng Mar 3, 2023
5c90f93
added scrollbar
NLmeng Mar 3, 2023
b7e12ef
fixed dimension problem, expand smoother
NLmeng Mar 3, 2023
47b84ef
fix bug with lowerhsv and apply precommit
NLmeng Mar 4, 2023
e188fb5
Merge branch 'main' into abhi/hsvsliders
NLmeng Mar 4, 2023
c3968ce
revert
NLmeng Mar 4, 2023
0c64b53
reverted some commits
NLmeng Mar 4, 2023
bc467bb
Revert "fix bug with lowerhsv and apply precommit"
NLmeng Mar 4, 2023
d1b4970
recommit 'fixed dimension problem, expand smoother, fix bug with lowe…
NLmeng Mar 4, 2023
be8fd0d
add masked
NLmeng Mar 4, 2023
be7c5d5
retrieve mask from every algorithm and display
NLmeng Mar 11, 2023
c00d0f4
added sys and path
NLmeng Mar 18, 2023
3e926ea
seesaw version 2
zoeyzhao57 Mar 11, 2023
f167676
seesaw version 2 update
zoeyzhao57 Mar 11, 2023
e7d2c56
seesaw version 2 update
zoeyzhao57 Mar 18, 2023
0e3c0dd
autopep8 action fixes (#72)
github-actions[bot] Mar 11, 2023
3881924
seesaw version 2 update
zoeyzhao57 Mar 25, 2023
65ec752
add seesaw2 to gui
NLmeng Apr 1, 2023
7fe691a
changed hsv to sliders and add color canvas for each
NLmeng Apr 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ omegaconf = "*"
numpy = "*"
tk = "*"
python-rospkg = "*"
Pillow = "*"

[dev-packages]

Expand Down
207 changes: 133 additions & 74 deletions Pipfile.lock

Large diffs are not rendered by default.

13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,17 @@
- example : `python create_dataset.py -v sim` or `python create_dataset.py -v crop -i 60 -o`

`test_pf.py:`

- runs performance tests on any of the algorithms against any video
- runs performance tests on algorithms against any video with an optional GUI
- reports `framerate`, `time-to-finish`, `vanishing point uptime`, `avg time to process frame`
- arguments :
- `-a/--alg` : name of algorithm
- `hough`, `center_row`, `mini_contour`, `mini_contour_downward`, `scanning`, `check_row_end` or `center_down`
- `hough`, `center_row`, `mini_contour`, `mini_contour_downward`, `scanning`, `seesaw`, `seesaw_v2`, or `check_row_end`
- `-v/--vid` : name of video
- video has to be stored in `./videos/`
- video configuration has to be stored as a `yaml` at `./config/video/`
- `-s/--show` : process drawings and show frame
- example : `python test_pf.py -a center_row -v farm4`

- `-s/--show` : creates a GUI that shows the frame, allow filter, toggle between views, adjust saturation, brightness, upper, and lower HSV
- example : `python test_pf.py -a seesaw -v crop -s`
### Commands to Start World in Gazebo

Run the following Commands the first time:
Expand Down Expand Up @@ -120,4 +119,4 @@ image shows the resulting lines we detected.

We are currently using these lines and calculating their intersection which occurs at vanishing point. Then we are using
a PID controller to minimimize the distance of this vanishing point from the center of our frame. Using this method, we
are able to centre our chassis over the crop rows we are traversing.
are able to centre our chassis over the crop rows we are traversing.
14 changes: 13 additions & 1 deletion algorithms/CenterRowAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import cv2 as cv
import numpy as np
from algorithms.Algorithm import Algorithm

from algorithms.Algorithm import Algorithm
from algorithms.utils import Lines


Expand All @@ -18,6 +18,7 @@ def __init__(self, config):
# masking range for green
self.LOW_GREEN = np.array(config.lower_hsv_threshold)
self.HIGH_GREEN = np.array(config.upper_hsv_threshold)
# print(self.LOW_GREEN, self.HIGH_GREEN)

# filtering parameters
self.averaging_kernel_size = config.averaging_kernel_size
Expand All @@ -44,6 +45,17 @@ def __init__(self, config):
self.center = None
self.center_angle = 0

def get_extra_content(self, frame, show):
maskf = self.create_binary_mask(frame)
item1, item2 = self.process_frame(frame, show)
return item1, item2, maskf

def update_lower_hsv(self, next):
self.LOW_GREEN = np.array(next)

def update_upper_hsv(self, next):
self.HIGH_GREEN = np.array(next)

def process_frame(self, frame, show):
"""Uses contouring to create contours around each crop row and uses these contours to find centroid lines,
row vanishing point, a center contour and the angle between the center contour and vanishing point\n
Expand Down
11 changes: 11 additions & 0 deletions algorithms/CheckRowEnd.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ def __init__(self, config):
# Percentage of empty rows required to register as row end
self.percentage_of_empty_rows = config.percentage_of_empty_rows

def get_extra_content(self, frame, show):
maskf = self.create_binary_mask(frame)
item1, item2 = self.process_frame(frame, show)
return item1, item2, maskf

def update_lower_hsv(self, next):
self.LOW_GREEN = np.array(next)

def update_upper_hsv(self, next):
self.HIGH_GREEN = np.array(next)

def process_frame(self, frame, show):
"""Averages values in each row in a mask of the frame. If the number of rows with an average value
of zero is greater than req_rows_empty, then frame is row end\n
Expand Down
11 changes: 11 additions & 0 deletions algorithms/HoughAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ def __init__(self, config):
# resize factor
self.RESIZE_FACTOR = config.resize_factor

def get_extra_content(self, frame, show):
maskf = self.create_mask(frame)
item1, item2 = self.process_frame(frame, show)
return item1, item2, maskf

def update_lower_hsv(self, next):
self.LOW_GREEN = np.array(next)

def update_upper_hsv(self, next):
self.HIGH_GREEN = np.array(next)

# processFrame function that is called to process a frame of a video
# takes in frame mat object obtained from cv2 video.read()
def process_frame(self, frame, show=True):
Expand Down
27 changes: 22 additions & 5 deletions algorithms/MiniContoursAlgorithm.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import cv2
import numpy as np
import time
import math
import operator
import sys
import math
from algorithms.utils import Lines
import time

import cv2
import numpy as np

from algorithms.Algorithm import Algorithm
from algorithms.utils import Lines


cmask = ""
class MiniContoursAlgorithm(Algorithm):
# applies hsv binarization to the image
# slices the image into horizontal strips and finds all the contours in each strip
Expand Down Expand Up @@ -106,6 +109,8 @@ def get_center_hough_lines(

mask = cv2.inRange(cv2.cvtColor(frame, cv2.COLOR_BGR2HSV), self.low_green, self.high_green)
mask = cv2.medianBlur(mask, 9)
global cmask
cmask = mask
# mask = cv2.GaussianBlur(mask, (9,9), 10)
# mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, self.morphology_kernel)
centroids = self.get_centroids(mask, num_strips=num_strips)
Expand Down Expand Up @@ -199,6 +204,18 @@ def get_center_hough_lines(

return frame, lines, point_lines

def get_extra_content(self, frame, show):
global cmask
# maskf = self.create_binary_mask(frame)
item1, item2 = self.process_frame(frame, show)
return item1, item2, cmask

def update_lower_hsv(self, next):
self.LOW_GREEN = np.array(next)

def update_upper_hsv(self, next):
self.HIGH_GREEN = np.array(next)

def process_frame(self, original_frame, num_strips=60, show=False):

# original_frame: BGR frame
Expand Down
15 changes: 15 additions & 0 deletions algorithms/MiniContoursDownwards.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import math
from algorithms.utils import Lines

cmask = ""

class MiniContoursDownwards():

Expand Down Expand Up @@ -144,6 +145,8 @@ def get_best_fit_line(self, frame, show, num_strips=60, dist_type=cv2.DIST_L2, p
else:
line = None

global cmask
cmask = c_mask
if show:
cv2.imshow('frame', frame)
cv2.imshow('mask', mask)
Expand All @@ -152,6 +155,18 @@ def get_best_fit_line(self, frame, show, num_strips=60, dist_type=cv2.DIST_L2, p

return frame, line

def get_extra_content(self, frame, show):
global cmask
# maskf = self.create_binary_mask(frame)
item1, item2 = self.process_frame(frame, show)
return item1, item2, cmask

def update_lower_hsv(self, next):
self.LOW_GREEN = np.array(next)

def update_upper_hsv(self, next):
self.HIGH_GREEN = np.array(next)

def process_frame(self, original_frame, num_strips=60, show=False):
"""""
parameters:
Expand Down
11 changes: 11 additions & 0 deletions algorithms/ScanningAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ def create_line(self, start_x, start_y, end_x, end_y):

return line

def get_extra_content(self, frame, show):
item1, item2 = self.process_frame(frame, show)
maskf = frame
return item1, item2, maskf

def update_lower_hsv(self, next):
self.LOW_GREEN = np.array(next)

def update_upper_hsv(self, next):
self.HIGH_GREEN = np.array(next)

def process_frame(self, frame, show):

hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
Expand Down
11 changes: 11 additions & 0 deletions algorithms/SeesawAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ def __init__(self, config):
self.HEIGHT = int(config.frame_length)
self.WIDTH = int(config.frame_width)

def get_extra_content(self, frame, show):
maskf = self.create_binary_mask(frame)
item1, item2 = self.process_frame(frame, show)
return item1, item2, maskf

def update_lower_hsv(self, next):
self.LOW_GREEN = np.array(next)

def update_upper_hsv(self, next):
self.HIGH_GREEN = np.array(next)

def process_frame(self, frame, show):

black_frame, points, both_points = self.plot_points(frame)
Expand Down
164 changes: 164 additions & 0 deletions algorithms/SeesawAlgorithmVersionTwo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import math
import cv2 as cv
import numpy
import numpy as np
from algorithms.Algorithm import Algorithm
from helper_scripts.change_res import change_res


class SeesawAlgorithmVersionTwo(Algorithm):

def __init__(self, config):
"""
Sets seesaw algorithm configurations
:param config: config params
"""
# masking range for green
self.LOW_GREEN = np.array(config.lower_hsv_threshold)
self.HIGH_GREEN = np.array(config.upper_hsv_threshold)

# filtering parameters
self.averaging_kernel_size = config.averaging_kernel_size
self.gauss_kernel_size = list(map(int, config.gauss_kernel_size.split(',')))
self.dilate_kernel_size = config.dilate_kernel_size
self.sigma_x = config.sigma_x

# dimensions
self.HEIGHT = int(config.frame_length)
self.WIDTH = int(config.frame_width)

# visual parameters
self.BAR_HEIGHT = config.bar_height
self.RES_FACTOR = config.resolution_factor

def get_extra_content(self, frame, show):
maskf = self.create_binary_mask(frame)
item1, item2 = self.process_frame(frame, show)
return item1, item2, maskf

def update_lower_hsv(self, next):
self.LOW_GREEN = np.array(next)

def update_upper_hsv(self, next):
self.HIGH_GREEN = np.array(next)

def process_frame(self, frame, show):
"""
Divides screen into horizontal strips and find average location of green for each strip.
Draw the best fit line based the average location,
then calculate the angle between the best fit line and a horizontal line.
:param frame: current frame (mat)
:param show: show/hide frames on screen for debugging
:type show: bool
:return: processed frame (mat), angle [-90, 90]
"""

frame = change_res(frame, self.RES_FACTOR)
black_frame, average_points, overall_bias = self.plot_points(frame)
average_points = np.array(average_points)

if average_points.any():
"""get best fit line for centre points"""
[vx, vy, x, y] = cv.fitLine(average_points, cv.DIST_L2, 0, 0.01, 0.01)
x1 = int(x - vx * self.WIDTH)
x2 = int(x + vx * self.WIDTH)
y1 = int(y - vy * self.HEIGHT)
y2 = int(y + vy * self.HEIGHT)
black_frame = cv.line(black_frame, (x1, y1), (x2, y2), (0, 255, 255), 9)

# calculate angle
if y1 - y2 != 0:
angle = round(math.degrees(math.atan(int(x2 - x1) / int(y1 - y2))), 1)
bias = round(numpy.average(overall_bias)/(self.WIDTH/2)*90, 2)

if abs(angle) > abs(bias):
output = angle
else:
output = bias
else:
output = None
else:
output = None

black_frame = self.print_text(frame, str(output))

return black_frame, output

def plot_points(self, frame):
"""
Divides screen into horizontal strips, and find average location of green for each strip.
:param frame: current frame (mat)
:return: processed frame (mat), list of centre points
"""
frame = cv.line(frame, (int(self.WIDTH/2), 0), (int(self.WIDTH/2), int(self.HEIGHT)), (255, 0, 255), 9)
bar_height = int(self.BAR_HEIGHT)
mask = self.create_binary_mask(frame)

square_low = 0
square_high = bar_height

black_frame = frame

centre_points = []
overall_bias = []

while square_low < self.HEIGHT:
points = []

seg = mask[int(square_low) + 1:int(square_high), 0:self.WIDTH]

condition = (seg == 255)
points = np.where(condition)[1]

if points.any():
centre = int(numpy.median(points))
bias = int(centre - self.WIDTH/2)
black_frame = cv.circle(black_frame, [int(centre), int((square_high + square_low) / 2)],
radius=0, color=(0, 0, 255), thickness=15)
centre_points.append([centre, int((square_high + square_low) / 2)])
overall_bias.append(bias)

square_high += bar_height
square_low += bar_height

return frame, centre_points, overall_bias

def print_text(self, frame, text):

# Define the font and text size
font = cv.FONT_HERSHEY_SIMPLEX
font_scale = 1

# Define the color and thickness of the text
color = (255, 255, 255) # in BGR format
thickness = 2

# Get the size of the text box
text_size, _ = cv.getTextSize(text, font, font_scale, thickness)

# Calculate the position of the text box
x = int((frame.shape[1] - text_size[0]) / 4)
y = int((frame.shape[0] + text_size[1]) / 4)

# Draw the text on the image
cv.putText(frame, text, (x, y), font, font_scale, color, thickness)

return frame

def create_binary_mask(self, frame):
"""
:param frame: current frame
:return: binary mask of frame made using self.low_green and self.high_green as the HSV range
"""

# Run averaging filter to blur the frame
kernel = np.ones((5, 5), np.float32) / 25
frame = cv.filter2D(frame, -1, kernel)

# Convert to hsv format to allow for easier colour filtering
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

# Filter image and allow only shades of green to pass
mask = cv.inRange(hsv, self.LOW_GREEN, self.HIGH_GREEN)

return mask
Loading