From 717b044430b4e1a0def59264c6795141f0a0fb15 Mon Sep 17 00:00:00 2001 From: caroline Date: Fri, 8 Apr 2022 15:54:22 +0200 Subject: [PATCH] intial commit --- CMakeLists.txt | 207 ++++++++++++++ package.xml | 71 +++++ .../hsv_toolbar_ros.cpython-38.pyc | Bin 0 -> 3124 bytes scripts/hsv_toolbar_ros.py | 116 ++++++++ scripts/initial_opencv.py | 14 + scripts/initial_row_detection.py | 102 +++++++ scripts/initial_test.py | 265 ++++++++++++++++++ scripts/opencv_tutorial.py | 91 ++++++ scripts/rotation_problem.py | 24 ++ scripts/row_detection_tutorial.py | 104 +++++++ 10 files changed, 994 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 package.xml create mode 100644 scripts/__pycache__/hsv_toolbar_ros.cpython-38.pyc create mode 100755 scripts/hsv_toolbar_ros.py create mode 100755 scripts/initial_opencv.py create mode 100755 scripts/initial_row_detection.py create mode 100755 scripts/initial_test.py create mode 100755 scripts/opencv_tutorial.py create mode 100755 scripts/rotation_problem.py create mode 100755 scripts/row_detection_tutorial.py diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cf72635 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,207 @@ +cmake_minimum_required(VERSION 3.0.2) +project(navigation_crop_row) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + roscpp + rospy + sensor_msgs + std_msgs +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# sensor_msgs# std_msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES navigation_crop_row +# CATKIN_DEPENDS roscpp rospy sensor_msgs std_msgs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/navigation_crop_row.cpp +# ) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/navigation_crop_row_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# catkin_install_python(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_navigation_crop_row.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..a558fb4 --- /dev/null +++ b/package.xml @@ -0,0 +1,71 @@ + + + navigation_crop_row + 0.0.0 + The navigation_crop_row package + + + + + caroline + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + roscpp + rospy + sensor_msgs + std_msgs + roscpp + rospy + sensor_msgs + std_msgs + roscpp + rospy + sensor_msgs + std_msgs + + + + + + + + diff --git a/scripts/__pycache__/hsv_toolbar_ros.cpython-38.pyc b/scripts/__pycache__/hsv_toolbar_ros.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f65615d3f3d19e18a1869a3b64d88de8e6812f90 GIT binary patch literal 3124 zcmb_e&2!sC6yKFBe}5%$zLVDZXsAoEA+%gzfHtKK(@xTj>6BAFu zrCdAH6Ekp%kGXT^?_hR@6Q}$OT;Q$bq;5L2IUtSRd;6r_{q67VzNc?;xio^S`sYUD zK^~#MRAcx`K;uhz_#YS{f(Z7I8EI_du&tR|sC83+tsOICVcRg{L+>>&(N3DlcFIg) zHIDA3+Zi(x+A%NN&Y3x|4Kq*TW`QKkB0=^DJfrZ8(V|_V1$!Kx36eA?Ny?leX>*!n z%o&n3XGzYSBYAV46wE6$`5c*7Ns)~Fgv>G-C1ao$NQsPtUL+G_67&+8BGaIk$qbnV zeT~eKdC)5~{}S_28asZET>693uMOy9~;kzoG15XJ&3+J90@Ql&|T|D>9g9lbjm(D%2 z;28tY^10^pX$#RH6KmLeZQ`SrT{qKNnwU2;nTt}6a zQx)@#iYAk5`*)d3npEb_tgjdgSOrVtY1idK8DF>UCVhJP5A-?x4MZ=unlU- zy1v!rHO`!xZ|}QJTdm!4SkSRp(5-QYxgEi4ExvDwAn;&j@bhZtKu*DT5dhI*l(#G~ zfVQO89S4E*7|vrh4%VdzLW-iv{~(AZVVFvSWkCTq_76;D0hUt&vH+5qh^lbitf<^0 zN~ncLqNKi>2GoNOFTk$A>tWba(7qJxx5jk0`Sr-X^7wU7u-++Awh8rea<)+sNS6NG)sxWi?42D3*m|&HE zd!s_z(GL;Pi2g!5!q1R@BZfq5H_h&2bOc$umlejLrfSSHbQ^Nok@lnZE&2}mAVvH* zL1Jngu#$&Z#CKAC?MR1K`cM}ckrlaZUF1bU6u0%heiVZ@BVzOr_hIDF9y^RFTjk1% zvC%6!wg=hB*)4NnGeL>WbZpMyWCVN77G(S)q1l0 z>H6D&%r(N|VFh6UkU6*AZ1W~$I}36y)1i|zI?VM&7zvr^+OBv=4`kBW7i)nRFep2l zk2arJcON`iU9WG+gzG=C{U(hPRCs8@K&s5e!qZe%gT~!9Zv|aBHptvgREb{g$%-Lk z#1^&*Gg+>xUlLO@wap;kTWX?0WJcK_@W{nnS8(7e!-H4p>>$s@_tqM~QkYKOnT`(QQ!+*Jm-Py_Ta$H8Vpc z2f~@M{lGtH2Yb9%+JIhVmq(FT^Hr*R~d$5Q79TqbSS?AVM`b{!TbW5NY4 z)LD{-zt@Hhp!pq{0%oJ|GYwuv(H?11sFH#mSg;Rx6$Fc^eg#f_9*5Wv?r@ getting gradient, magnitude & direction +#3. Non-maximum Suppression: scan to remove unwanted pixels (not constituting edge) +# checking if pixel is local maximum in its neighbourhood in direction of gradient +# => binary image with hin edges +#4. Hysteresis Thresholding: threshold values maxVal & minVal to determine edges & non-edges (discarded) +# edges between values are only edges if connected to to "sure-edges" +# also removes small pixels as edges are assumed to be long lines +gscale = cv2.Canny(gscale,280,290,apertureSize = 3) #(input image, minVal, maxVal, aperture_size=size of Sobel kernel to find image gradients: default=3) +# default L2gradient=False => Edge_Gradient(G)=|G_x|+|G_y|; True => Edge_Gradient(G)=sqrt(G_x²+G_y²) +gscale2 = cv2.Canny(gscale,100,290,apertureSize = 3) +gscale3 = cv2.Canny(gscale,250,290,apertureSize = 3) +gscale4 = cv2.Canny(gscale,280,350,apertureSize = 3) + +""" plt.figure() +plt.plot(), plt.imshow(gscale) +plt.title('Canny Edge-Detection Results') +plt.xticks([]), plt.yticks([]) +plt.show() """ + +## +plt.subplot(221) +plt.plot(),plt.imshow(gscale) +plt.title('Canny Edge-Detection 1'), plt.xticks([]), plt.yticks([]) +plt.subplot(222) +plt.plot(),plt.imshow(gscale2) +plt.title('Canny Edge-Detection 2'), plt.xticks([]), plt.yticks([]) +plt.subplot(223) +plt.plot(),plt.imshow(gscale3) +plt.title('Canny Edge-Detection 3'), plt.xticks([]), plt.yticks([]) +plt.subplot(224) +plt.plot(),plt.imshow(gscale4) +plt.title('Canny Edge-Detection 4'), plt.xticks([]), plt.yticks([]) +plt.show() +## + + +size = np.size(gscale) #returns the product of the array dimensions +skel = np.zeros(gscale.shape,np.uint8) #array of zeros +ret,gscale = cv2.threshold(gscale,128,255,0) #thresholding the image +#(grayscale source image, threshod value to classify pixel values, max value, type of thresholding) +#output: threshold that was used, thresholded image + +element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3)) # get kernel: (shape,size,anchor=new cv.Point(-1.-1)) +# anchor position [-1,-1] at center of image, only cross-shaped element depends on anchor position +done = False +while not done: + eroded = cv2.erode(gscale,element) # erodes away boundaries of foreground object & removes small noise + temp = cv2.dilate(eroded,element) # increase object area + temp = cv2.subtract(gscale,temp) # subtract images of same type & depth + skel = cv2.bitwise_or(skel,temp) + gscale = eroded.copy() + zeros = size - cv2.countNonZero(gscale) + if zeros==size: + done = True + + +lines = cv2.HoughLines(skel,1,np.pi/180,130) #lines=vector storing lines (r,theta) +#(output of edge detector, resolution of r in pixels, resolution of theta in rad, threshold: min # of intersections, srn & stn) +a,b,c = lines.shape + +#draw the lines +for i in range(a): + rho = lines[i][0][0] + theta = lines[i][0][1] + a = np.cos(theta) + b = np.sin(theta) + x0 = a*rho + y0 = b*rho + x1 = int(x0 + 1000*(-b)) + y1 = int(y0 + 1000*(a)) + x2 = int(x0 - 1000*(-b)) + y2 = int(y0 - 1000*(a)) + + cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2, cv2.LINE_AA) + #display lines: image, point1, point2, color, thickness int, line type, shift) + +plt.subplot(121)#OpenCV reads images as BGR, this corrects so it is displayed as RGB +plt.plot(),plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) +plt.title('Row Detection'), plt.xticks([]), plt.yticks([]) +plt.subplot(122) +plt.plot(),plt.imshow(skel,cmap='gray') +plt.title('Skeletal Image'), plt.xticks([]), plt.yticks([]) +plt.show() \ No newline at end of file diff --git a/scripts/initial_test.py b/scripts/initial_test.py new file mode 100755 index 0000000..6f8a481 --- /dev/null +++ b/scripts/initial_test.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# run bagfile: rosbag play -l 'filename' +# run python script: python3 initial_test.py + +import roslib +import sys +import argparse +import rospy +import cv2 +import time +from std_msgs.msg import String +from sensor_msgs.msg import Image +from cv_bridge import CvBridge, CvBridgeError +import numpy as np +import matplotlib.pyplot as plt +#import hsv_toolbar_ros as tb + +LAB_boolean = True +HSV_boolean = True +RGB_boolean = True + +def rescale_frame(frame, percent): + width = int(frame.shape[1] * percent/ 100) + height = int(frame.shape[0] * percent/ 100) + dim = (width, height) + return cv2.resize(frame, dim, interpolation =cv2.INTER_AREA) + +#class Image_Segmentation(): + + +class Image_Receiver(): + + def __init__(self): + #rospy.init_node('zed_image_left', anonymous=True) + self.bridge = CvBridge() + rospy.Subscriber("/zed/zed_node/left/image_rect_color", Image, self.callback) + plt.ion() + + def region_selection(self,image): + rows, columns = image.shape[:2] + bottom_left = [0*columns /6, 6*rows / 6] + top_left = [1.5*columns / 6, 2*rows /6] + bottom_right = [6*columns / 6, 6*rows / 6] + top_right = [4.5*columns / 6, 2*rows / 6] + polygons = np.array([[bottom_left, top_left, top_right, bottom_right]], dtype=np.int32) + + mask = np.zeros_like(image) + cv2.fillPoly(mask,polygons,(255,255,255)) + masked_image = cv2.bitwise_and(image,mask) + return masked_image + + def otsu(self,images): + otsu_threshold = [] + image_result = [] + for i in range(len(images)): + threshold, result = cv2.threshold(images[i], 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) + otsu_threshold.append(threshold) + image_result.append(result) + return otsu_threshold, image_result + + def display_binary(self,images,color_space, rescale): + color_spaces = ", ".join(color_space) + images_rescaled = images + if rescale == True: + for i in range(len(images)): + images_rescaled[i] = rescale_frame(images[i],30) + horizontal_concat = [] + for i in range(1,len(images),3): + horizontal_concat.append(np.concatenate((images_rescaled[i-1], images_rescaled[i], images_rescaled[i+1]), axis=1)) + cube_concat = horizontal_concat[0] + for i in range(1,len(horizontal_concat)): + cube_concat = np.concatenate((cube_concat,horizontal_concat[i]), axis=0) + cv2.imshow('Binary Otsu Images for '+color_spaces+' color space', cube_concat) + + def hough(self,images,RGBimage): + RGBimages = [] + hough_lines = [] + for i in range(len(images)): + RGBimages.append(RGBimage) + for i in range(len(images)): + lines = cv2.HoughLines(images[i],1,np.pi/180,200) + + for rho,theta in lines[0]: + a = np.cos(theta) + b = np.sin(theta) + x0 = a*rho + y0 = b*rho + x1 = int(x0 + 1000*(-b)) + y1 = int(y0 + 1000*(a)) + x2 = int(x0 - 1000*(-b)) + y2 = int(y0 - 1000*(a)) + + cv2.line(RGBimages[i],(x1,y1),(x2,y2),(0,0,255),2,cv2.LINE_AA) + hough_lines.append(lines) + return RGBimages, hough_lines + + def hough_linesP(self,image, binary_images): + RGBimages = [] + hough_lines = [] + for i in range(len(binary_images)): + RGBimages.append(image) + for i in range(len(binary_images)): + lines = cv2.HoughLinesP(binary_images[i],2,np.pi/120,10,minLineLength=250,maxLineGap=75) + for line in lines: + x1,y1,x2,y2 = line[0] + cv2.line(image,(x1,y1),(x2,y2),(255,255,0),3) + line_img = np.zeros((image.shape[0], image.shape[1], 3), dtype=np.uint8) + hough_lines.append(lines) + #cv2.imshow("line_img",image) + return image, hough_lines + + def hough_lineP(self,image, green_image): + lines = cv2.HoughLinesP(green_image,2,np.pi/120,10,minLineLength=250,maxLineGap=75) + for line in lines: + x1,y1,x2,y2 = line[0] + cv2.line(image,(x1,y1),(x2,y2),(255,255,0),3) + line_img = np.zeros((image.shape[0], image.shape[1], 3), dtype=np.uint8) + #cv2.imshow("line_img",image) + return image + + def Rgb_space(self,image): + rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + R,G,B = cv2.split(rgb_image) + hist = self.histogram(rgb_image,["R","G","B"]) + + def Lab_space(self,image): + lab_image = cv2.cvtColor(image, cv2.COLOR_BGR2LAB) + L,A,B = cv2.split(lab_image) + hist = self.histogram(lab_image,["L","A","B"]) + + return lab_image,L,A,B + + def Hsv_space(self,image): + hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) + H,S,V = cv2.split(hsv_image) + hist = self.histogram(hsv_image,["H","S","V"]) + + """ + plt.clf() + plt.subplot(131) + plt.title("L") + plt.imshow(L) + plt.subplot(132) + plt.title("a") + plt.imshow(A) + plt.subplot(133) + plt.title("b") + plt.imshow(B) + plt.draw() + plt.pause(0.005) + """ + return hsv_image,H,S,V + + def callback(self, image_data): + try: + self.left_image = self.bridge.imgmsg_to_cv2(image_data, "bgr8") + except CvBridgeError as e : + print(e) + rescaled = rescale_frame(self.left_image,75) + denoised_image = cv2.GaussianBlur(rescaled, (5, 5), 0) + cv2.imshow("original_image", denoised_image) + print('Image size: {width}x{height}'.format(width=rescaled.shape[0],height=rescaled.shape[1])) + roi_image = self.region_selection(denoised_image) + color_image = roi_image + channels = [] + color_spaces = [] + if RGB_boolean == True: + color_image,chR,chG,chB = self.Lab_space(roi_image) + channels.extend([chR,chG,chB]) + color_spaces.extend(["R","G","B"]) + if LAB_boolean == True: + color_image,chL,chA,chB = self.Lab_space(roi_image) + channels.extend([chL,chA,chB]) + color_spaces.extend(["L","A","B"]) + if HSV_boolean == True: + color_image,chH,chS,chV = self.Hsv_space(roi_image) + channels.extend([chH,chS,chV]) + color_spaces.extend(["H","S","V"]) + if channels and color_spaces: + otsu_threshold, otsu_result = self.otsu(channels) + print("Obtained thresholds: ",otsu_threshold) + self.display_binary(otsu_result,color_spaces,True) + #hough_images, lines = self.hough(otsu_result,roi_image)# + #hough_images, lines = self.hough_linesP(roi_image, otsu_result) + #self.display_binary(hough_images,color_spaces,False) + hough_lines = self.hough_lineP(otsu_result[0],otsu_result[0]) + cv2.imshow("Hough Line P Function", hough_lines) + cv2.waitKey(3) + + #frame_threshold = cv2.inRange(color_image, (tb.low_H, tb.low_S, tb.low_V), (tb.high_H, tb.high_S, tb.high_V)) + + #cv2.imshow(window_capture_name, cv_image) + #cv2.imshow(window_detection_name, frame_threshold) + + def histogram(self,image,name): + # create the histogram plot, with three lines, one for + # each color + # plt.clf() + plt.figure() + plt.xlim([0, 256]) + for i in range(3): + hist = cv2.calcHist([image],[i],None,[256], [0,256]) + plt.plot(hist) + plt.legend(name) + plt.title("Color Histogram")#of legend color space + plt.xlabel("Color value") + plt.ylabel("Pixel count") + plt.show() + return hist + + #plt.draw() + plt.pause(0.005) + cv2.waitKey(0) # übergangsweise + plt.close('all') + +def main(): + + #Start the node imageprocessing + rospy.init_node('zed_image_left', anonymous=True) + #calls the function that OpenCV requires + detector = Image_Receiver() + + rate = rospy.Rate(10) # 10hz + #TODOPublish the offset value obtained from the front subscriber + + + #Keep the node alive unti; keyboard interrupt + try: + rospy.spin() + except KeyboardInterrupt: + rospy.loginfo("Detector node terminated.") + print("Shutting down") + cv2.destroyAllWindows() + +# Execution guard for python files +if __name__ == '__main__': + main() + +""" + +def imshow(img): + cv2.imshow("..",img) + cv2.waitKey(0) + cv2.destroyAllWindows() + +img = cv2.imread('/home/andrew/Desktop/camera/crop_row_detection/images/behrImages/first.jpg') +img = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) +while True: + resized_image = rescale_frame(img,25) + #imshow(resized_image) + L,A,B=cv2.split(resized_image) + cv2.imshow("L_Channel",L) # For L Channel + cv2.imshow("A_Channel",A) # For A Channel (Here's what You need) + cv2.imshow("B_Channel",B) # For B Channel + ch = cv2.waitKey(1) + if ch == 27: + break + cv2.waitKey(5) + +cv2.waitKey(0) +cv2.destroyAllWindows() + + +""" diff --git a/scripts/opencv_tutorial.py b/scripts/opencv_tutorial.py new file mode 100755 index 0000000..1b66aa7 --- /dev/null +++ b/scripts/opencv_tutorial.py @@ -0,0 +1,91 @@ +#!/usr/bin/python3 +# https://pyimagesearch.com/2018/07/19/opencv-tutorial-a-guide-to-learn-opencv/ +# import the necessary packages +import cv2 +import imutils +import numpy as np +import argparse + +def rescale_frame(frame, percent): # rescale image considering aspect ratio + width = int(frame.shape[1] * percent/ 100) + height = int(frame.shape[0] * percent/ 100) + dim = (width, height) + return cv2.resize(frame, dim, interpolation =cv2.INTER_AREA) + # alternative: resized = imutils.resize(image, width=300) => give goal height or width + +def extract_channels(image,color_space): + (ch1,ch2,ch3) = cv2.split(image) + cv2.imshow("Channel "+color_space[0],ch1) + cv2.imshow("Channel "+color_space[1],ch2) + cv2.imshow("Channel "+color_space[2],ch3) + +def rotate_bound(image, angle): + (h, w) = image.shape[:2] # image dimesnsions + (cX, cY) = (w // 2, h // 2) # center of image + M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0) # neg angle to rotate clockwise + cos = np.abs(M[0, 0]) # cos & sin value from rotation matrix + sin = np.abs(M[0, 1]) + # compute the new bounding dimensions of the image + nW = int((h * sin) + (w * cos)) + nH = int((h * cos) + (w * sin)) + # adjust the rotation matrix to take into account translation + M[0, 2] += (nW / 2) - cX + M[1, 2] += (nH / 2) - cY + # perform the actual rotation and return the image + return cv2.warpAffine(image, M, (nW, nH)) + + +# load the input image and show its dimensions, keeping in mind that +# images are represented as a multi-dimensional NumPy array with +# shape no. rows (height) x no. columns (width) x no. channels (depth) +image = cv2.imread('/home/caroline/Pictures/first.jpg') #numpy array + +# resize image ignoring aspect ratio +resized_image = cv2.resize(image, (300, 300)) +cv2.imshow("Fixed Resizing", resized_image) +cv2.waitKey(0) + +image = rescale_frame(image,20) + + +(h, w, d) = image.shape #height=rows, width=columns, depth=channels => 3 for RGB +print("width={}, height={}, depth={}".format(w, h, d)) +# display the image to our screen -- we will need to click the window +# open by OpenCV and press a key on our keyboard to continue execution +cv2.imshow("Image", image) +cv2.waitKey(0) + +# grayscale value 0-255 +# (B, G, R) with range [0, 255] + +# access the RGB pixel located at x=50, y=100, keepind in mind that +# OpenCV stores images in BGR order rather than RGB +(B, G, R) = image[100, 50] +print("R={}, G={}, B={}".format(R, G, B)) + +# array slicing and cropping +# extract a 100x100 pixel square ROI (Region of Interest) from the +# input image starting at x=320,y=60 at ending at x=420,y=160 +""" roi = image[60:160, 320:420] +cv2.imshow("ROI", roi) +cv2.waitKey(0) """ + +# transform image into different color spaces and split channels +""" image_lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB) +extract_channels(image_lab,"LAB") # lightness, red/green value, blue/yellow value => very vast color space +cv2.waitKey(0) +image_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # hue:color 0°-360°, saturation: amount of grey 0-1, value: brightness/intensity 0-1 +extract_channels(image_hsv,"HSV") +cv2.waitKey(0) """ + +# rotate image +# loop over rotation angles without cutting image +""" for angle in np.arange(0, 360, 30): # range [0, 360] in 15° increments + rotated = rotate_bound(image, angle) + cv2.imshow("Rotated", rotated) + cv2.waitKey(0) """ + +# blurring: reduce high-frequency noise => gaussianBlur function +blurred = cv2.GaussianBlur(image, (11, 11), 0) # 11x11 kernel: larger kernel create more blurry images +cv2.imshow("Blurred", blurred) +cv2.waitKey(0) \ No newline at end of file diff --git a/scripts/rotation_problem.py b/scripts/rotation_problem.py new file mode 100755 index 0000000..42cba28 --- /dev/null +++ b/scripts/rotation_problem.py @@ -0,0 +1,24 @@ +#!/usr/bin/python3 +#https://pyimagesearch.com/2017/01/02/rotate-images-correctly-with-opencv-and-python/ + +import numpy as np +import argparse +import imutils +import cv2 + +# construct the argument parse and parse the arguments +""" ap = argparse.ArgumentParser() +ap.add_argument("-i", "--image", required=True, + help="path to the image file") +args = vars(ap.parse_args()) """ + +image = cv2.imread('/home/caroline/Pictures/first.jpg') +gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) +gray = cv2.GaussianBlur(gray, (3, 3), 0) +edged = cv2.Canny(gray,90, 200) + +resized_image = cv2.resize(edged, (800, 800)) +cv2.imshow("Edged", resized_image) +cv2.waitKey(0) + +# further tutorial on rotating and cutting off... \ No newline at end of file diff --git a/scripts/row_detection_tutorial.py b/scripts/row_detection_tutorial.py new file mode 100755 index 0000000..589bfd6 --- /dev/null +++ b/scripts/row_detection_tutorial.py @@ -0,0 +1,104 @@ +#!/usr/bin/python3 +# Crop row navigation for autonomous field robot + +import cv2 +import numpy as np +import matplotlib.pyplot as plt +import sys + +def rescale_frame(frame, percent): # rescale image considering aspect ratio + width = int(frame.shape[1] * percent/ 100) + height = int(frame.shape[0] * percent/ 100) + dim = (width, height) + return cv2.resize(frame, dim, interpolation =cv2.INTER_AREA) + +image = cv2.imread('/home/caroline/Pictures/first.jpg') +image=rescale_frame(image, 20) + +### TBD: add Gaussian Blurr + +### Image Segmentation + +## RGB +# apply mask that generates grayscale image highlighting green ROIs +b,g,r = cv2.split(image) +gscale = 2*g-r-b + +""" cv2.imshow("Image after ExG mask is applied", gscale) +cv2.waitKey(0) """ + + +# obtain binary image by applying intensity threshold +""" color = ('b','g','r') +for i,col in enumerate(color): + hist = cv2.calcHist(image,[i],None,[256], [0,256])# image histogram + plt.plot(hist, color=col) + plt.title('Histogram of initial image') +plt.show() +cv2.waitKey(0) """ + + +""" hist2 = cv2.calcHist(gscale,[0],None,[256], [0,256])# image histogram +plt.plot(hist2,'k') +plt.title('Histogram of grayscale image') +plt.show() +cv2.waitKey(0) """ + +ret2,gscale2 = cv2.threshold(gscale,127,225,0) +ret,gscale = cv2.threshold(gscale,180,200,0) +""" cv2.imshow("Binary image", gscale) +cv2.waitKey(0) """ + +while True: + Hori = np.concatenate((gscale, gscale2), axis=1) # left and right image + cv2.imshow('Comparing Different Thresholds', Hori) + cv2.waitKey(1) + if cv2.waitKey(1) & 0xFF == ord('q'): + break + +cv2.destroyAllWindows() + +## YUV +# get U and V Layer +image_yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV) +(Y,U,V) = cv2.split(image_yuv) +task=2 #1: Layers; 2: histogram, 3: binary image, 4: combined layers +if task==1: + while True: + cv2.imshow("U-Layer",U) + cv2.imshow("V-Layer",V) + cv2.waitKey(1) + if cv2.waitKey(1) & 0xFF == ord('q'): + break + cv2.destroyAllWindows() + +elif task==2: + for i in range(2): + hist_yuv = cv2.calcHist(image_yuv,[i],None,[256], [0,256]) + plt.plot(hist_yuv) + plt.legend('U' 'V') + plt.title('Histogram of U and V Layer') + plt.show() + cv2.waitKey(0) + +elif task==3: + ret_u,binary_u = cv2.threshold(U,120,130,0) + ret_v,binary_v = cv2.threshold(V,125,135,0) + while True: + binary_uv = np.concatenate((binary_u, binary_v), axis=1) + cv2.imshow('U and V layer as binary image', binary_uv) + cv2.waitKey(1) + if cv2.waitKey(1) & 0xFF == ord('q'): + break + cv2.destroyAllWindows() + +elif task==4: + uv_combi = cv2.bitwise_and(binary_u,binary_v) + cv2.imshow('U and V layer as binary image', uv_combi) + cv2.waitKey(0) + + + + + +