├── 2018 └── get_light_type.py ├── .gitattributes ├── __pycache__ ├── kmeans.cpython-37.pyc ├── get_object.cpython-37.pyc ├── judge_color.cpython-37.pyc └── judge_diretcton.cpython-37.pyc ├── .idea ├── vcs.xml ├── misc.xml ├── modules.xml ├── detet_traffic_light.iml └── workspace.xml ├── README.md ├── main_all_in.py ├── .gitignore ├── kmeans.py ├── judge_color.py ├── judge_diretcton.py ├── main_test_ZED_with_yolov3.py ├── get_object.py └── yzn_judge_light.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /__pycache__/kmeans.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangzhaonan18/detect_traffic_light/HEAD/__pycache__/kmeans.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/get_object.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangzhaonan18/detect_traffic_light/HEAD/__pycache__/get_object.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/judge_color.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangzhaonan18/detect_traffic_light/HEAD/__pycache__/judge_color.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/judge_diretcton.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangzhaonan18/detect_traffic_light/HEAD/__pycache__/judge_diretcton.cpython-37.pyc -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 红绿灯检测 2 | 3 | ## 1.环境 4 | - py37 5 | - opencv 3.4.2 6 | - win10 + pycharm 7 | 8 | ## 2.程序作用:判断红绿灯的颜色和方向。 9 | 10 | ### 具体说明如下: 11 | 12 | 0. 为了方便复制程序,已经将所有的程序放入这个py文件中了,程序测试正常。修改前请备份,谢谢。 13 | 1. 输入是的一个只包含红绿灯的图片(注意,不是摄像头读取的整个图),输出是红绿灯的颜色+方向+置信度。 14 | 2. 颜色用字符表示:红色是"R", 黄色是"Y", 绿色是"G", 未知或不能判断是"X"。 15 | 3. 方向用字符表示:圆饼灯是"C",左转箭头是"L",直行箭头是"D",右转箭头是"R",未知或不能判断是"X"。 16 | 4. 置信度用[0,1]之间的两位小数表示,数值越大,正确率越高。如0.86 17 | 18 | ## 3. 函数说明 19 | 20 | ## 4. demo 21 | 22 | https://www.bilibili.com/video/av53928579/ 23 | -------------------------------------------------------------------------------- /.idea/detet_traffic_light.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /main_all_in.py: -------------------------------------------------------------------------------- 1 | # -*- coding=utf-8 -*- 2 | # py37 3 | # opencv 3.4.1 4 | # win10 + pycharm 5 | 6 | import time 7 | 8 | import cv2 9 | 10 | from get_object import get_object 11 | from judge_diretcton import judge_direction 12 | from judge_color import judge_color 13 | 14 | 15 | # judge_light 是一个总函数,同时调用了三个函数:get_object,judge_direction,udge_color 16 | def judge_light(trafficLight): 17 | obj_bgr, cnt_max, cx, cy = get_object(trafficLight) # 通过颜色来获取红绿灯区域。(目前只考虑了一个红绿灯的情况) 18 | if cnt_max is None: 19 | return "X", "X", 0 20 | direction, direction_conf = judge_direction(obj_bgr, cnt_max) # 判断方向 21 | # print("\nResult : \ndirection, ratio = ", direction, direction_conf) 22 | color, color_conf = judge_color(trafficLight, obj_bgr, cx, cy) # 判断颜色 23 | 24 | # print("color, color_conf = ", color, color_conf) 25 | conf = round(direction_conf * color_conf, 2) # 将反向和颜色置信度的成绩作为最后的置信度。 26 | 27 | return color, direction, conf # 单个字符, 单个字符, 小于1的小数 28 | 29 | 30 | if __name__ == "__main__": 31 | trafficLight = cv2.imread('C:\\Users\\qcdz-003\\Pictures\\light\\001.jpg', cv2.IMREAD_COLOR) 32 | # cv2.imshow("trafficLight", trafficLight) 33 | start = time.time() 34 | color, direction, conf = judge_light(trafficLight) # 最终只使用这一行代码。 35 | end = time.time() 36 | print("judge_light() use time = ", end - start) # 0.00297 37 | print("color, direction, conf = ", color, direction, conf) 38 | print("the end !") 39 | cv2.waitKey() 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | .idea/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | pip-wheel-metadata/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # celery beat schedule file 95 | celerybeat-schedule 96 | 97 | # SageMath parsed files 98 | *.sage.py 99 | 100 | # Environments 101 | .env 102 | .venv 103 | env/ 104 | venv/ 105 | ENV/ 106 | env.bak/ 107 | venv.bak/ 108 | 109 | # Spyder project settings 110 | .spyderproject 111 | .spyproject 112 | 113 | # Rope project settings 114 | .ropeproject 115 | 116 | # mkdocs documentation 117 | /site 118 | 119 | # mypy 120 | .mypy_cache/ 121 | .dmypy.json 122 | dmypy.json 123 | 124 | # Pyre type checker 125 | .pyre/ 126 | -------------------------------------------------------------------------------- /kmeans.py: -------------------------------------------------------------------------------- 1 | # -*- coding=utf-8 -*- 2 | # K-means 图像分割 连续图像分割 (充分利用红绿灯的特点) 3 | 4 | import cv2 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | 9 | def seg_kmeans_color(img, k=2): 10 | 11 | # 变换一下图像通道bgr->rgb,否则很别扭啊 12 | h, w, d = img.shape # (595, 1148, 3) # 0.47 聚类的时间和图像的面积大小成正比,即与图像的点数量成正比。 13 | b, g, r = cv2.split(img) 14 | img = cv2.merge([r, g, b]) 15 | 16 | # 3个通道展平 17 | img_flat = img.reshape((img.shape[0] * img.shape[1], 3)) # 一个通道一列,共三列。每行都是一个点。 18 | img_flat = np.float32(img_flat) 19 | # print("len of img_flat = ", len(img_flat)) 20 | # 迭代参数 21 | criteria = (cv2.TERM_CRITERIA_EPS + cv2.TermCriteria_MAX_ITER, 20, 0.5) 22 | flags = cv2.KMEANS_RANDOM_CENTERS 23 | 24 | # 聚类 25 | 26 | compactness, labels, centers = cv2.kmeans(img_flat, k, None, criteria, 10, flags) 27 | # print(" len of labels = ", len(labels)) 28 | # print(labels) # 每个点的标签 29 | # print(centers) # 两类的中心,注意是点的值,不是点的坐标 30 | labels = np.squeeze(labels) 31 | img_output = labels.reshape((img.shape[0], img.shape[1])) 32 | L1 = max(int(img.shape[1] / 4), 2) # 当图像只有四个像素时, L1等于1 会出现-1:的异常异常,所以需要改为2, 33 | 34 | # 取每个四个角上的点 35 | boundary00 = np.squeeze(img_output[0:L1, 0: L1]. reshape((1, -1))) 36 | boundary01 = np.squeeze(img_output[0:L1, - L1:]. reshape((1, -1))) 37 | boundary10 = np.squeeze(img_output[- L1:, 0:L1]. reshape((1, -1))) 38 | boundary11 = np.squeeze(img_output[- L1:, - L1-1]. reshape((1, -1))) 39 | 40 | # 取中间一个正方形内的点 41 | inter = img_output[L1: -L1, L1: -L1] 42 | boundary_avg = np.average(np.concatenate((boundary00, boundary01, boundary10, boundary11), axis=0)) 43 | inter_avg = np.average(inter) 44 | print("boundary_avg", boundary_avg) 45 | print("inter_avg", inter_avg) 46 | 47 | if k == 2 and boundary_avg > inter_avg: # 如果聚类使得边缘类是1,即亮的话,需要纠正颜色(所有的标签)。 48 | img_output = abs(img_output - 1) # 将边缘类(背景)的标签值设置为0,中间类(中间类)的值设置为1. 49 | 50 | img_output = np.array(img_output, dtype=np.uint8) # jiang 51 | 52 | return img_output 53 | 54 | 55 | if __name__ == '__main__': 56 | 57 | img = cv2.imread('C:\\Users\\qcdz-003\\Pictures\\light\\007.jpg', cv2.IMREAD_COLOR) 58 | 59 | img_output = seg_kmeans_color(img, k=2) # 2 channel picture 60 | 61 | # print(img_output.shape) # (244, 200) 62 | # 显示结果 63 | 64 | plt.subplot(121), plt.imshow(img), plt.title('input') 65 | plt.subplot(122), plt.imshow(img_output, 'gray'), plt.title('kmeans') 66 | plt.show() 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /judge_color.py: -------------------------------------------------------------------------------- 1 | from get_object import get_object 2 | import cv2 3 | import numpy as np 4 | 5 | 6 | def judge_light_color(obj_bgr): 7 | # 将图片转成HSV的 8 | obj_hsv = cv2.cvtColor(obj_bgr, cv2.COLOR_BGR2HSV) 9 | # 从H通道中提取出颜色的平均值 10 | H = obj_hsv[:, :, 0] 11 | H = np.squeeze(np.reshape(H, (1, -1))) 12 | 13 | # print(H) # 这里要注意红色H值得范围很特别,特别小和特别大都是红色,直接取平均值会出现判断错误的情况。 14 | H_value = np.array([]) 15 | for i in H: 16 | if i > 0 and i < 124: 17 | H_value = np.append(H_value, i) 18 | elif i > 155: # 将大于155的红色的H值,都看成是1,方便处理 19 | H_value = np.append(H_value, 1.0) 20 | H_avg = np.average(H_value) 21 | 22 | # 根据这个值来判断是什么颜色, RYG 23 | if H_avg <= 18 or H_avg >= 156: 24 | color = "R" 25 | elif H_avg >= 18 and H_avg <= 34: 26 | color = "Y" 27 | elif H_avg >= 35 and H_avg <= 100: 28 | color = "G" 29 | else: 30 | color = "X" 31 | 32 | return color 33 | 34 | 35 | def judge_light_position(trafficLight, cx, cy): 36 | h, w, d = trafficLight.shape 37 | # print(trafficLight.shape) 38 | position = "0" 39 | if max(w / h, h / w) > 2: # 根据位置来判断颜色 40 | if h > w: # 竖着三个灯 41 | if cy < h / 3: # 灯的中心在上方 42 | position = "1" 43 | elif cy < 2 * h / 3: # 灯的中心在中间 44 | position = "2" 45 | else: # 灯的中心在下方 46 | position = "3" 47 | 48 | else: # 横着三个灯 49 | if cx < w / 3: # 灯的中心在左方 50 | position = "1" 51 | elif cx < 2 * w / 3: # 灯的中心在中间 52 | position = "2" 53 | else: # 灯的中心在右方 54 | position = "3" 55 | return position 56 | 57 | 58 | def judge_color(trafficLight, obj_bgr, cx, cy): 59 | position = judge_light_position(trafficLight, cx, cy) # 判断位置 60 | color = judge_light_color(obj_bgr) # 判断颜色 61 | if (position == "1" and color == "R") or (position == "2" and color == "Y") or (position == "3" and color == "G"): 62 | color_conf = 1.0 63 | elif position == "2" and color == "R": 64 | color = "Y" # 如何在中间就纠正为黄色 65 | color_conf = 0.9 66 | elif position == "1" and color == "Y": 67 | color = "R" # 如何在中间就纠正为黄色 68 | color_conf = 0.9 69 | else: 70 | color_conf = 0.8 71 | return color, color_conf 72 | 73 | 74 | if __name__ == '__main__': 75 | trafficLight = cv2.imread('C:\\Users\\qcdz-003\\Pictures\\light\\023.jpg', cv2.IMREAD_COLOR) 76 | obj_bgr, cnt_max, cx, cy = get_object(trafficLight) 77 | 78 | color, color_conf = judge_color(trafficLight, obj_bgr, cx, cy) # 一行代码 79 | 80 | print("color, color_conf = ", color, color_conf) 81 | print("The end") 82 | -------------------------------------------------------------------------------- /judge_diretcton.py: -------------------------------------------------------------------------------- 1 | # -*- conding=utf-8 -*- 2 | # py37 3 | # 判断红绿灯的形状和方向 4 | 5 | from get_object import get_object 6 | import cv2 7 | import numpy as np 8 | 9 | 10 | def cal_circle_xy(frame, x, y, radius): 11 | x1 = x - radius if x - radius > 0 else 0 12 | x2 = x + radius if x + radius < frame.shape[1] else frame.shape[1] # cv里面横坐标是x 是shape[1] 13 | y1 = y - radius if y - radius > 0 else 0 14 | y2 = y + radius if y + radius < frame.shape[0] else frame.shape[0] # cv里面纵坐标是y 是shape[0] 15 | return int(x1), int(x2), int(y1), int(y2) 16 | 17 | 18 | def cal_point(SomeBinary, x, y, radius): # 返回最大方向的编号int 19 | 20 | x = int(x) 21 | y = int(y) 22 | x1, x2, y1, y2 = cal_circle_xy(SomeBinary, x, y, radius) 23 | S00 = SomeBinary[y1:y, x1:x] # 计算面积时,使用二值图,左上 24 | S01 = SomeBinary[y1:y, x:x2] # 右上 25 | S10 = SomeBinary[y:y2, x1:x] # 左下 26 | S11 = SomeBinary[y:y2, x:x2] # 右下 27 | 28 | SS00 = np.sum(S00) 29 | SS01 = np.sum(S01) 30 | SS10 = np.sum(S10) 31 | SS11 = np.sum(S11) 32 | 33 | value = [SS00, SS01, SS10, SS11] 34 | value.sort(reverse=True) # 将面积大的放在前面 35 | 36 | print("\nSS00, SS01 , SS10, SS11 = ", SS00, SS01, SS10, SS11) 37 | if SS00 in value[0:2] and SS10 in value[0:2]: 38 | return "R" # right 39 | elif SS01 in value[0:2] and SS11 in value[0:2]: # 箭头右侧需要补齐的东西多 40 | return "L" # left 41 | elif SS10 in value[0:2] and SS11 in value[0:2]: 42 | return "D" # direct 43 | else: 44 | return "X" # circle 45 | 46 | 47 | def judge_direction(obj_bgr, cnt_max): 48 | 49 | cnt = np.array(cnt_max) 50 | ((x, y), radius) = cv2.minEnclosingCircle(cnt) # 确定面积最大的轮廓的外接圆 返回圆心坐标和半径 51 | if radius < 3: 52 | print("\nminEnclosingCircle radius = ", radius, "< 5 , so NO direction !! ", ) 53 | return "X", 0.0 54 | 55 | area = cv2.contourArea(cnt) # 轮廓面积 56 | hull = cv2.convexHull(cnt) # 计算出凸包形状(计算边界点) 57 | hull_area = cv2.contourArea(hull) # 计算凸包面积 58 | solidity = round(float(area) / hull_area, 2) # 自己的面积 / 凸包面积 凸度 59 | circularity = round(hull_area / (np.pi * pow(radius, 2)), 2) # 自己的面积/外接圆的面积 60 | 61 | print("solidity = ", solidity) 62 | print("circularity = ", circularity) 63 | 64 | direction = "X" # X 表示是未知方向,或者不能正确判断 65 | ratio = 0 66 | threshold01 = 0.9 # solidity 远大越可能是圆 67 | threshold03 = 0.5 # solidity * circularity 越小越可能是箭头 68 | 69 | if solidity > threshold01 and circularity > 0.5: # 当solidity度很大,且圆形度不是很小时 (考虑椭圆的情况),直接判断为圆 70 | direction = "C" # 判断 为圆形灯 71 | ratio = solidity # 将solidity度作为 圆灯的概率返回 72 | elif solidity > threshold01 and circularity <= 0.5: # 凸度很大,但圆形度很小时,说明不是圆 73 | direction = "X" 74 | ratio = 0.0 75 | else: # 当solidity度处于中间值时,判断为箭头,并计算概率 76 | # (规定圆形度与凸度成绩小于0.7时,概率为1。大于0.7时,概率小于1) 77 | cnts_ColorThings = cv2.drawContours(obj_bgr.copy(), [cnt], -1, (255, 255, 255), -1) 78 | hull_ColorThings = cv2.drawContours(obj_bgr.copy(), [hull], -1, (255, 255, 255), -1) 79 | BinThings = ~cnts_ColorThings & hull_ColorThings & ~obj_bgr # 找到凸包与原图之间的差 80 | 81 | # cv2.imshow("obj_bgr", obj_bgr) 82 | # cv2.imshow("cnts_ColorThings = ", cnts_ColorThings) 83 | # cv2.imshow("BinThings = ", BinThings) 84 | direction = cal_point(BinThings, int(x), int(y), radius) # 判断方向(圆心和半径)根据凸包与原图之间的差,计算箭头的方向 85 | x = solidity * circularity 86 | print("solidity * circularity = ", x) 87 | if x < threshold03: # 乘积小于这个值,判断为箭头,概率为1。 88 | ratio = 1 89 | else: 90 | ratio = (x - 1) / (threshold03 - 1) 91 | # 当圆形度特别小时,判断为处于异常,输出X 0 92 | return direction, ratio 93 | 94 | 95 | if __name__ == '__main__': 96 | trafficLight = cv2.imread('C:\\Users\\qcdz-003\\Pictures\\light\\027.jpg', cv2.IMREAD_COLOR) 97 | obj_bgr, cnt_max = get_object(trafficLight) 98 | direction = judge_direction(obj_bgr, cnt_max) 99 | 100 | # cv2.imshow("trafficLight", trafficLight) 101 | # cv2.imshow("obj_bgr", obj_bgr) 102 | 103 | # print("direction", direction) 104 | cv2.waitKey() 105 | print("the end") 106 | -------------------------------------------------------------------------------- /main_test_ZED_with_yolov3.py: -------------------------------------------------------------------------------- 1 | # -*- coding=utf-8 -*- 2 | # py37 3 | 4 | from detect import * 5 | from get_light_type import get_light_type 6 | import cv2 7 | 8 | from yzn_judge_light import judge_light 9 | 10 | 11 | if __name__ == "__main__": 12 | parser = argparse.ArgumentParser() 13 | # parser.add_argument("--image_folder", type=str, default="data/samples", help="path to dataset") 14 | parser.add_argument("--model_def", type=str, default="config/yolov3.cfg", help="path to model definition file") 15 | parser.add_argument("--weights_path", type=str, default="weights/yolov3.weights", help="path to weights file") 16 | parser.add_argument("--class_path", type=str, default="data/coco.names", help="path to class label file") 17 | parser.add_argument("--conf_thres", type=float, default=0.8, help="object confidence threshold") 18 | parser.add_argument("--nms_thres", type=float, default=0.4, help="iou thresshold for non-maximum suppression") 19 | # parser.add_argument("--batch_size", type=int, default=1, help="size of the batches") 20 | # parser.add_argument("--n_cpu", type=int, default=0, help="number of cpu threads to use during batch generation") 21 | parser.add_argument("--img_size", type=int, default=416, help="size of each image dimension") 22 | # parser.add_argument("--checkpoint_model", type=str, help="path to checkpoint model") 23 | opt = parser.parse_args() 24 | # print(opt) 25 | 26 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 27 | 28 | os.makedirs("output", exist_ok=True) 29 | 30 | # Set up model 31 | model = Darknet(opt.model_def, img_size=opt.img_size).to(device) 32 | 33 | if opt.weights_path.endswith(".weights"): 34 | # Load darknet weights 35 | model.load_darknet_weights(opt.weights_path) 36 | else: 37 | # Load checkpoint weights 38 | model.load_state_dict(torch.load(opt.weights_path)) 39 | 40 | model.eval() # Set in evaluation mode # 设置为评估模式 41 | 42 | # dataloader = DataLoader( 43 | # ImageFolder(opt.image_folder, img_size=opt.img_size), 44 | # batch_size=opt.batch_size, 45 | # shuffle=False, 46 | # num_workers=opt.n_cpu, 47 | # ) 48 | 49 | classes = load_classes(opt.class_path) # Extracts class labels from file 50 | 51 | Tensor = torch.cuda.FloatTensor if torch.cuda.is_available() else torch.FloatTensor 52 | 53 | imgs = [] # Stores image paths 54 | img_detections = [] # Stores detections for each image index 55 | 56 | # detect object from ZED carmer 57 | 58 | capture = cv2.VideoCapture(0) 59 | batch_i = 0 60 | while(True): 61 | batch_i += 1 62 | # 获取一帧 63 | ret, frame = capture.read() 64 | h, w, d = frame.shape 65 | frame = frame[0:416, 0:416] # 双目摄像头只显示其中的一半 66 | # frame = frame[0:h, 0:int(w / 2)] # 双目摄像头只显示其中的一半 67 | 68 | transform2 = transforms.Compose([transforms.ToTensor(), ]) 69 | input_imgs = transform2(frame) 70 | # input_imgs = torch.FloatTensor(frame) 71 | print("\n", "##" * 66) 72 | print("Performing object detection:") 73 | prev_time = time.time() 74 | # for batch_i, (img_paths, input_imgs) in enumerate(dataloader): # 遍历一个 bach_size 中的每一张图片 75 | # Configure input 76 | # input_imgs = Variable(input_imgs.type(Tensor)) 77 | input_imgs = Variable(input_imgs.type(Tensor).unsqueeze(0)) 78 | 79 | # Get detections 80 | with torch.no_grad(): # ???????????????????? 81 | detections = model(input_imgs) # 预测一张图片的检测结果 82 | detections = non_max_suppression(detections, opt.conf_thres, opt.nms_thres) # 非极大抑制(一张图片上的) 83 | 84 | # Log progress 85 | current_time = time.time() 86 | inference_time = datetime.timedelta(seconds=current_time - prev_time) 87 | prev_time = current_time 88 | print("\t+ Batch %d, Inference Time: %s" % (batch_i, inference_time)) 89 | 90 | # Draw bounding boxes and labels of detections 91 | frame_copy = frame.copy() 92 | if detections[0] is not None: 93 | # Rescale boxes to original image 94 | # detections = rescale_boxes(detections, opt.img_size, frame.shape[:2]) 95 | # unique_labels = detections[:, -1].cpu().unique() 96 | # n_cls_preds = len(unique_labels) 97 | print("Have detect object !!") 98 | for detection in detections: 99 | for x1, y1, x2, y2, conf, cls_conf, cls_pred in detection: # 只输出检测到红绿灯的情况。 100 | if cls_pred == 9: 101 | print("This is a traffic light") 102 | trafficLight = frame[int(y1): int(y2), int(x1):int(x2)] 103 | # trafficLight = frame[int(y1) + 2: int(y2) - 2, int(x1) + 2:int(x2)-2] 104 | 105 | # type = get_light_type(trafficLight_05) # 去年的方法 106 | color, direction, conf = judge_light(trafficLight) # 今年的新方法,获取红绿灯区域。(目前只考虑了一个红绿灯的情况) 107 | 108 | frame_copy = cv2.rectangle(frame_copy, (x1, y1), (x2, y2), (0, 255, 0), 2) 109 | font = cv2.FONT_HERSHEY_SIMPLEX 110 | 111 | # frame_copy = cv2.putText(frame_copy, classes[int(cls_pred)], (x1, y1), font, 1.2, (0, 0, 255), 2) 112 | 113 | frame_copy = cv2.putText(frame_copy, color + direction + "+" + str(conf), (x1, y1), font, 0.6, (0, 0, 255), 2) 114 | 115 | else: 116 | print("No object or cant detect") 117 | cv2.imshow('frame_copy', frame_copy) 118 | if cv2.waitKey(1) == ord('q'): 119 | break 120 | 121 | -------------------------------------------------------------------------------- /get_object.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import time 4 | import matplotlib.pyplot as plt 5 | from kmeans import seg_kmeans_color 6 | 7 | 8 | def find_contours_max(img_bin_color): 9 | # 找最大轮廓的正矩形 10 | gray = cv2.cvtColor(img_bin_color, cv2.COLOR_BGR2GRAY) # 转成灰色图像 11 | ret, BinThings = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 灰色图像二值化(变黑白图像) 12 | _, contours, hierarchy = cv2.findContours(BinThings, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) 13 | 14 | # for i in range(len(contours) - 1): # 绘制每一个轮廓 15 | # cv2.drawContours(frame_copy, [contours[i+1]], -1, (0, 0, 255), 2) 16 | 17 | # if len(contours) > 0: 18 | # cnt_max = max(contours, key=cv2.contourArea) # 找到面积最大的轮廓 19 | # color_aera = cv2.contourArea(cnt_max) 20 | 21 | if len(contours) > 0: 22 | cnt_max = max(contours, key=cv2.contourArea) # 找到面积最大的轮廓 23 | # cv2.drawContours(img_bgr, [cnt_max], -1, (0, 255, 255), 2) 24 | # # ((x, y), radius) = cv2.minEnclosingCircle(np.array(cnt_max)) 25 | # cv2.circle(img_bgr, (int(x), int(y)), int(radius), (0, 0, 255), 2) 26 | # print(((x, y), radius)) 27 | 28 | # print("cnt_max", cnt_max) 29 | return cnt_max 30 | return None 31 | 32 | 33 | def crop_max_region(frame_bgr, img_bin_color): # frame_bgr, img_bgr 34 | """ 35 | :param frame_bgr: 用于裁剪的原始图片 36 | :param img_bin_color: # 用于腐蚀,寻找颜色区域的 37 | :return: 在原图上裁剪下来的区域。 38 | """ 39 | 40 | cnt_max = find_contours_max(img_bin_color) 41 | if cnt_max is not None: 42 | x, y, w, h = cv2.boundingRect(np.array(cnt_max)) # 正外界矩形 43 | # print("x, y, w, h = ", x, y, w, h) 44 | # cv2.rectangle(img_bgr, (x, y), (x + w, y + h), (0, 255, 0), 2) 45 | frame_crop = frame_bgr[y: y + h, x: x + w] 46 | 47 | # cv2.imshow("frame_crop6", frame_crop) 48 | cnt_max = find_contours_max(frame_crop) 49 | 50 | # 将原始图像翻转并判断形状和方向 51 | 52 | return frame_crop, cnt_max, x, y, w, h 53 | return None, None, None, None, None, None 54 | 55 | def get_color_region(frame_bgr, frame_hsv, color="RYG"): 56 | # cv2.imshow("frame_bgr", frame_bgr) 57 | # colorLower = np.array([0, 43, 46], dtype=np.uint8) # 非黑白灰的 58 | # colorUpper = np.array([180, 255, 255], dtype=np.uint8) 59 | try: 60 | redLower01 = np.array([0, 43, 46], dtype=np.uint8) # 部分红 和橙黄绿 61 | redUpper01 = np.array([124, 255, 255], dtype=np.uint8) 62 | red_mask02_and_othersLower = np.array([156, 43, 46], dtype=np.uint8) # 部分红 63 | red_mask02_and_othersUpper = np.array([180, 255, 255], dtype=np.uint8) 64 | 65 | red_mask01 = cv2.inRange(frame_hsv, redLower01, redUpper01) 66 | red_mask02_and_others = cv2.inRange(frame_hsv, red_mask02_and_othersLower, red_mask02_and_othersUpper) 67 | mask = None 68 | if color == "RYG": 69 | mask = red_mask01 + red_mask02_and_others 70 | # print("mask.shape = ", mask.shape) # (26, 23) 71 | 72 | BinColors = cv2.bitwise_and(frame_bgr, frame_bgr, mask=mask) 73 | # cv2.imshow("BinColors", BinColors) 74 | # BinColors = cv2.GaussianBlur(BinColors, (5, 5), 0) # 彩色图时 高斯消除噪音 # 很耗时,不建议使用 75 | 76 | # dst = cv2.erode(dst, None, iterations=2) # 腐蚀操作 77 | kernel = np.ones((5, 5), np.uint8) 78 | img_bin_color = cv2.morphologyEx(BinColors, cv2.MORPH_OPEN, kernel) # 开运算 79 | # kernel = np.ones((10, 10), np.uint8) 80 | img_bin_color = cv2.morphologyEx(img_bin_color, cv2.MORPH_CLOSE, kernel) # 闭运算 81 | 82 | # cv2.imshow("mask ", mask) # 这是一个二值图 83 | # cv2.imshow("crop_frame ", crop_frame) # 这是一个二值图 84 | 85 | # cv2.imshow("BinColors", BinColors) # 原图 86 | # cv2.imshow("crop_frame", crop_frame) # 原图 87 | # cv2.imshow("BinColors", BinColors) # 其中的彩色区域 88 | # cv2.imshow("img_bin_color ", img_bin_color) 89 | 90 | # cv2.waitKey(0) 91 | return crop_max_region(frame_bgr, img_bin_color) 92 | except: 93 | return None, None, None, None, None, None 94 | 95 | 96 | def get_object(frame_bgr): 97 | frame_hsv = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2HSV) 98 | frame_crop_bgr, _, x1, y1, w1, h1 = get_color_region(frame_bgr, frame_hsv, color="RYG") # 获取彩色区域(裁剪一个矩形) 99 | if frame_crop_bgr is None: 100 | print("no object in get_object") 101 | return None, None, None, None 102 | frame_kmeans = seg_kmeans_color(frame_crop_bgr) # k menan k=2 103 | 104 | # cv2.imshow("frame_crop_bgr", frame_crop_bgr) 105 | # cv2.imshow("frame_kmeans", frame_kmeans) 106 | 107 | frame_new_bgr = cv2.bitwise_and(frame_crop_bgr, frame_crop_bgr, mask=frame_kmeans) # 使用Kmean之后的结果比直接使用颜色阈值分割更可靠。 108 | 109 | kernel = np.ones((3, 3), np.uint8) 110 | frame_new_bgr = cv2.morphologyEx(frame_new_bgr, cv2.MORPH_OPEN, kernel) 111 | frame_max_bgr, cnt_max, x2, y2, w2, h2 = crop_max_region(frame_new_bgr, frame_new_bgr) # Kmeans之后的中间颜色区域提取。 112 | 113 | # light = frame_bgr[y1 + y2: y1 + y2 + h2, x1 + x2: x1 + x2 + w2] 114 | # cv2.imshow("light =", light) 115 | 116 | cx = int(x1 + x2 + w2 / 2) # 灯的中心点坐标 117 | cy = int(y1 + y2 + h2 / 2) 118 | 119 | # # 显示结果 120 | # b, g, r = cv2.split(frame_bgr) 121 | # frame_rgb = cv2.merge([r, g, b]) 122 | # frame_crop_rgb = frame_crop_bgr[:, :, (2, 1, 0)] 123 | # frame_new_rgb = frame_new_bgr[:, :, (2, 1, 0)] 124 | # frame_max_rgb = frame_max_bgr[:, :, (2, 1, 0)] 125 | # 126 | # # plt 显示图片RGB的顺序 127 | # # plt.subplot(161), plt.imshow(frame_rgb), plt.title('rgb') # plt是RGB的顺序,CV是BGR的顺序。 128 | # # plt.subplot(162), plt.imshow(frame_crop_rgb), plt.title('crop_rgb') # plt是RGB的顺序,CV是BGR的顺序。 129 | # # plt.subplot(163), plt.imshow(frame_kmeans, 'gray'), plt.title('kmeans') 130 | # # plt.subplot(164), plt.imshow(frame_new_rgb, 'gray'), plt.title('new_rgb') 131 | # # plt.subplot(165), plt.imshow(frame_max_rgb), plt.title('max_rgb') 132 | # # plt.show() 133 | 134 | # cv显示图片 BGR的通道顺序 135 | # cv2.imshow("frame", frame) # 原图 136 | # cv2.imshow("crop_frame", frame_crop) # 原图 137 | # cv2.waitKey(0) 138 | # frame_crop_gray = cv2.cvtColor(frame_crop_bgr, cv2.COLOR_BGR2GRAY) 139 | # cv2.imshow("frame_crop_gray", frame_crop_gray) 140 | # cv2.waitKey() 141 | return frame_max_bgr, cnt_max, cx, cy 142 | 143 | 144 | if __name__ == '__main__': 145 | frame_bgr = cv2.imread('C:\\Users\\qcdz-003\\Pictures\\light\\023.jpg', cv2.IMREAD_COLOR) 146 | 147 | frame_max_bgr, cnt = get_object(frame_bgr) 148 | # cv2.imshow("asdf", frame_max_bgr) 149 | cv2.waitKey() 150 | -------------------------------------------------------------------------------- /2018/get_light_type.py: -------------------------------------------------------------------------------- 1 | #! -*- coding=utf-8 -*- 2 | 3 | 4 | import cv2 5 | import numpy as np 6 | 7 | 8 | # judge_color 9 | 10 | def find_mask(frame, color): 11 | blackLower01 = np.array([0, 0, 0], dtype=np.uint8) # 黑的阈值 标准H:0:180 S:0:255 V:0:46:220 12 | blackUpper01 = np.array([180, 255, 90], dtype=np.uint8) 13 | blackLower02 = np.array([0, 0, 46], dtype=np.uint8) # 灰的阈值 标准H:0:180 S:0:43 V:0:46:220 14 | blackUpper02 = np.array([180, 43, 45], dtype=np.uint8) # 灰色基本没用 15 | 16 | redLower01 = np.array([0, 80, 80], dtype=np.uint8) # 红色的阈值 标准H:0-10 and 160-179 S:43:255 V:46:255 17 | redUpper01 = np.array([10, 255, 255], dtype=np.uint8) 18 | redLower02 = np.array([156, 80, 80], dtype=np.uint8) # 125 to 156 19 | redUpper02 = np.array([180, 255, 255], dtype=np.uint8) 20 | 21 | greenLower = np.array([40, 80, 80], dtype=np.uint8) # 绿色的阈值 标准H:35:77 S:43:255 V:46:255 22 | greenUpper = np.array([95, 255, 255], dtype=np.uint8) # V 60 调整到了150 23 | 24 | blueLower = np.array([105, 120, 46], dtype=np.uint8) # 蓝H:100:124 紫色H:125:155 25 | blueUpper = np.array([130, 255, 255], dtype=np.uint8) 26 | 27 | yellowLower = np.array([24, 80, 80], dtype=np.uint8) # 黄色的阈值 标准H:26:34 S:43:255 V:46:255 28 | yellowUpper = np.array([36, 255, 255], dtype=np.uint8) # 有的图 黄色变成红色的了 29 | try: 30 | hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 31 | red1_mask = cv2.inRange(hsv, redLower01, redUpper01) # 根据阈值构建掩膜, 红色的两个区域 32 | red2_mask = cv2.inRange(hsv, redLower02, redUpper02) 33 | red_mask = red1_mask + red2_mask 34 | 35 | black01_mask = cv2.inRange(hsv, blackLower01, blackUpper01) # 根据阈值构建掩膜,黑色的区域 36 | black02_mask = cv2.inRange(hsv, blackLower02, blackUpper02) # 根据阈值构建掩膜,黑色的区域 37 | black_mask = black01_mask + black02_mask 38 | 39 | yellow_mask = cv2.inRange(hsv, yellowLower, yellowUpper) # 根据阈值构建掩膜, 黄色的区域 40 | green_mask = cv2.inRange(hsv, greenLower, greenUpper) # 根据阈值构建掩膜, 绿色的区域 41 | 42 | blue_mask = cv2.inRange(hsv, blueLower, blueUpper) 43 | if color == "black": 44 | mask = black_mask 45 | elif color == "yellow": 46 | mask = yellow_mask 47 | elif color == "red": 48 | mask = red_mask 49 | elif color == "green": 50 | mask = green_mask 51 | elif color == "blue": 52 | mask = blue_mask 53 | elif color == "red+blue": 54 | mask = red_mask + blue_mask 55 | elif color == "yellow+green": 56 | mask = yellow_mask + green_mask 57 | elif color == "red+yellow+green": 58 | mask = red_mask + yellow_mask + green_mask 59 | else: 60 | mask = None 61 | return mask 62 | 63 | except: 64 | return None 65 | 66 | 67 | def find_color_aera(Crop_frame, color): 68 | 69 | mask = find_mask(Crop_frame, color) 70 | # mask = cv2.dilate(mask, None, iterations=1) # 膨胀操作,其实先腐蚀再膨胀的效果是开运算,去除噪点 71 | # mask = cv2.erode(mask, None, iterations=num) # 腐蚀操作 72 | BinColors = cv2.bitwise_and(Crop_frame, Crop_frame, mask=mask) # 提取感兴趣的颜色区域 背景黑色+彩色的图像 73 | 74 | dst = cv2.GaussianBlur(BinColors, (3, 3), 0) # 彩色图时 高斯消除噪音 75 | gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY) # 转成灰色图像 76 | 77 | ret, BinThings = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 灰色图像二值化(变黑白图像) 78 | 79 | # cv2.imshow("BinThings", BinThings) 80 | # cv2.waitKey(0) 81 | 82 | _, contours, hierarchy = cv2.findContours(BinThings, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) # 边界是封闭的 del first BinThings, 83 | if len(contours) > 0: 84 | cnt_max = max(contours, key=cv2.contourArea) # 找到面积最大的轮廓 85 | color_aera = cv2.contourArea(cnt_max) 86 | # cv2.imshow("BinThings", BinColors) 87 | # cv2.waitKey(0) 88 | else: 89 | color_aera = 0 90 | return color_aera 91 | 92 | 93 | def judge_color(Crop_frame): 94 | yellow_area = find_color_aera(Crop_frame, "yellow") 95 | red_area = find_color_aera(Crop_frame, "red") 96 | green_area = find_color_aera(Crop_frame, "green") 97 | print("\nyellow_area, red_area, green_area = ", yellow_area, red_area, green_area) 98 | ratio = 0.05 # 调参 99 | if max(yellow_area, red_area, green_area) > ratio * pow(min(Crop_frame.shape[0], Crop_frame.shape[1]), 2): # 提取出的图像的面积不能太小 100 | 101 | if yellow_area > red_area and yellow_area > green_area: 102 | return "yellow" 103 | if red_area > yellow_area and red_area > green_area: 104 | return "red" 105 | if green_area > yellow_area and green_area > red_area: 106 | return "green" 107 | else: 108 | print("\n max area = ", max(yellow_area, red_area, green_area), " < ", ratio, " * min^2 =", 0.1 * pow(min(Crop_frame.shape[0], Crop_frame.shape[1]), 2)) 109 | return "NO" 110 | 111 | # judge_direction 112 | 113 | 114 | def cal_circle_xy(frame, x, y, radius): 115 | x1 = x - radius if x - radius > 0 else 0 116 | x2 = x + radius if x + radius < frame.shape[1] else frame.shape[1] # cv里面横坐标是x 是shape[1] 117 | y1 = y - radius if y - radius > 0 else 0 118 | y2 = y + radius if y + radius < frame.shape[0] else frame.shape[0] # cv里面纵坐标是y 是shape[0] 119 | return int(x1), int(x2), int(y1), int(y2) 120 | 121 | 122 | def cal_point(SomeBinary, x, y, radius): # 返回最大方向的编号int 123 | 124 | x = int(x) 125 | y = int(y) 126 | x1, x2, y1, y2 = cal_circle_xy(SomeBinary, x, y, radius) 127 | S00 = SomeBinary[y1:y, x1:x] # 计算面积时,使用二值图,左上 128 | S01 = SomeBinary[y1:y, x:x2] # 右上 129 | S10 = SomeBinary[y:y2, x1:x] # 左下 130 | S11 = SomeBinary[y:y2, x:x2] # 右下 131 | 132 | SS00 = np.sum(S00) 133 | SS01 = np.sum(S01) 134 | SS10 = np.sum(S10) 135 | SS11 = np.sum(S11) 136 | 137 | value = [SS00, SS01, SS10, SS11] 138 | value.sort(reverse=True) # 将面积大的放在前面 139 | 140 | print("\nSS00, SS01 , SS10, SS11 = ", SS00, SS01, SS10, SS11) 141 | if SS00 in value[0:2] and SS10 in value[0:2]: 142 | return "R" # right 143 | elif SS01 in value[0:2] and SS11 in value[0:2]: # 箭头右侧需要补齐的东西多 144 | return "L" # left 145 | elif SS10 in value[0:2] and SS11 in value[0:2]: 146 | return "D" # direct 147 | else: 148 | return "X" # circle 149 | 150 | 151 | def find_cnt(Crop_frame, mask): # 找轮廓 152 | 153 | mask = cv2.dilate(mask, None, iterations=1) 154 | BinColors = cv2.bitwise_and(Crop_frame, Crop_frame, mask=mask) # 提取感兴趣的颜色区域 背景黑色+彩色的图像 155 | dst = cv2.GaussianBlur(BinColors, (3, 3), 0) # 彩色图时 高斯消除噪音 156 | gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY) # 转成灰色图像 157 | ret, BinThings = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 灰色图像二值化(变黑白图像) 158 | _, contours, hierarchy = cv2.findContours(BinThings, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) # 边界是封闭的 linux del first one 159 | cv2.imshow("asdf",BinThings ) 160 | if len(contours) > 0: 161 | cnt_max = max(contours, key=cv2.contourArea) # 找到面积最大的轮廓 162 | return cnt_max 163 | else: 164 | return None 165 | 166 | 167 | def judge_direction(Crop_frame): # 判断方向 168 | size = 50 169 | Crop_frame = cv2.resize(Crop_frame, (size, int(size * Crop_frame.shape[0] / Crop_frame.shape[1])), 170 | interpolation=cv2.INTER_CUBIC) # 将裁剪下来的图片调整到固定的尺寸 171 | # cv2.imshow("Crop_frame", Crop_frame) 172 | # cv2.waitKey(0) 173 | mask = find_mask(Crop_frame, "red+yellow+green") 174 | mask = cv2.erode(mask, None, iterations=2) # 腐蚀操作 175 | cnt_max = find_cnt(Crop_frame, mask) # 找到最大轮廓 176 | 177 | if cnt_max is None: 178 | print("\nno color contour, so NO direction !!") 179 | return "NO" 180 | solidity = 0.85 181 | direction = "NO" 182 | ilter_num = 1 183 | min_s = 0.8 # 比例最小值,低于这个值,直接判断为箭头信号灯 184 | max_s = 0.94 # 比例最大值,高于这个值,直接判断为圆形信号灯 185 | max_item = 4 # 最大腐蚀次数,比例介于最大值和最小值之间时,通过腐蚀来判断。 186 | while solidity > min_s and solidity < max_s and ilter_num < max_item: 187 | print("ilter_num = ", ilter_num) 188 | 189 | cnts = np.array(cnt_max) 190 | # cnts = cnt_max 191 | ((x, y), radius) = cv2.minEnclosingCircle(cnts) # 确定面积最大的轮廓的外接圆 返回圆心坐标和半径 192 | if radius < 5: 193 | print("\nminEnclosingCircle radius = ", radius, "< 5 , so NO direction !! ", ) 194 | return "NO" 195 | x = int(x) 196 | y = int(y) 197 | area = cv2.contourArea(cnts) # 轮廓面积 198 | hull = cv2.convexHull(cnts) # 计算出凸包形状(计算边界点) 199 | hull_area = cv2.contourArea(hull) # 计算凸包面积 200 | solidity = float(area) / hull_area # 轮廓面积 / 凸包面积 201 | print("\nsolidity = ", solidity) 202 | if solidity > max_s: 203 | direction = "C" # circle 204 | break 205 | # elif solidity < min_s: 206 | # direction = "" # others type not light 207 | # # print("direction = D ", solidity) 208 | # break 209 | 210 | cnts_ColorThings = Crop_frame.copy() 211 | hull_ColorThings = Crop_frame.copy() 212 | cnts_ColorThings = cv2.drawContours(cnts_ColorThings, [cnts], -1, (255, 255, 255), -1) 213 | hull_ColorThings = cv2.drawContours(hull_ColorThings, [hull], -1, (255, 255, 255), -1) 214 | BinThings = ~cnts_ColorThings & hull_ColorThings & ~Crop_frame # 找到凸包与原图之间的差 215 | 216 | 217 | 218 | direction = cal_point(BinThings, x, y, radius) # (圆心和半径)根据凸包与原图之间的差,计算箭头的方向 219 | ilter_num += 1 220 | cnt_max = find_cnt(Crop_frame, mask) # 找最大轮廓 221 | 222 | if cv2.contourArea(cnt_max) < size * size / 5: # 腐蚀到,剩余面积很小时,结束。 223 | break 224 | return direction 225 | 226 | 227 | def get_light_type(crop_frame): 228 | color = judge_color(crop_frame) # 颜色 229 | direction = judge_direction(crop_frame) # 方向 230 | print("\n color, direction = ", color, direction) 231 | 232 | if color == "red" and direction == "R": 233 | return "15" 234 | elif color == "green" and direction == "R": 235 | return "16" 236 | elif color == "yellow" and direction == "R": 237 | return "17" 238 | elif color == "red" and direction == "D": 239 | return "18" 240 | elif color == "green" and direction == "D": 241 | return "19" 242 | elif color == "yellow" and direction == "D": 243 | return "20" 244 | elif color == "red" and direction == "L": 245 | return "21" 246 | elif color == "green" and direction == "L": 247 | return "22" 248 | elif color == "yellow" and direction == "L": 249 | return "23" 250 | elif color == "red" and direction == "C": 251 | return "24" 252 | elif color == "green" and direction == "C": 253 | return "25" 254 | elif color == "yellow" and direction == "C": 255 | return "26" 256 | else: 257 | return "NO light or cant judge" 258 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 62 | 63 | 72 | 73 | 74 | 82 | 83 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 |