python输出graphml格式的图 如何用python输出jpg_opencv threshold

Image by Pexels from Pixabay

    原生YOLO是用C语言写的,有人已经将YOLO移植到了Python上,有各种框架的实现,今天教你不使用PyTorch、Tensorflow之类的框架,只使用OpenCV和Numpy将YOLO 3跑起来。

    我使用的OpenCV是4.4.0,3.X的版本我没试过,但是应该也可以跑,直接上代码。

"""此处源码来自https://www.learnopencv.com/deep-learning-based-object-detection-using-yolov3-with-opencv-python-c/这个连结不只包含Python代码,还有C++代码,我只整理(并且简化)了Python的部分"""import cv2import numpy as npclass OpenCVDarknet:    """运行YOLO进行图像物件识别的类"""    conf_threshold: float = 0.5  # 置信度阈值    nms_threshold: float = 0.4  # Non-maximum suppression threshold    inp_width: float = 416    inp_height: float = 416  # 输入图像的宽高    def __init__(self, model_configuration, model_weights, classes_file):        with open(classes_file, 'rt') as f:            self.classes = f.read().rstrip('\n').split('\n')        self.net = cv2.dnn.readNet(cv2.samples.findFile(model_weights),                                   cv2.samples.findFile(model_configuration),                                   'darknet')        # 或者上面写法换成这种        # self.net = cv2.dnn.readNetFromDarknet(model_configuration, model_weights)        self.net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)        self.net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)    def get_outputs_names(self, net):        """获取输出层的名称"""        # 获取网络中所有层的名称        layers_names = self.net.getLayerNames()        # 获取输出图层的名称        return [            layers_names[i[0] - 1] for i in self.net.getUnconnectedOutLayers()        ]    def draw_pred(self, image, class_id, conf, left, top, right, bottom):        """绘制预测的边界框"""        # 绘制一个边界框        cv2.rectangle(image, (left, top), (right, bottom), (0, 0, 255))        # 获取类别名称及其置信度的标签        if self.classes:            assert (class_id < len(self.classes))        label = '%s:%s' % (self.classes[class_id], format(conf, ".2%"))        # 在边框上方显示标签        label_size, base_line = cv2.getTextSize(label,                                                cv2.FONT_HERSHEY_SIMPLEX, 0.5,                                                1)        top = max(top, label_size[1])        cv2.putText(image, label, (left, top), cv2.FONT_HERSHEY_SIMPLEX, 1,                    (255, 255, 255))    def post_process(self, image, outs):        """移除低置信度的识别结果"""        image_height, image_width = image.shape[:2]        # 扫描从网络输出的所有边界框,并仅保留其中具有高置信度得分的。        # 向box赋予得分最高的类别标签。        class_ids, confidences, boxes = [], [], []        for out in outs:            for detection in out:                scores = detection[5:]                class_id = np.argmax(scores)                confidence = scores[class_id]                if confidence > self.conf_threshold:                    center_x = int(detection[0] * image_width)                    center_y = int(detection[1] * image_height)                    width = int(detection[2] * image_width)                    height = int(detection[3] * image_height)                    left = int(center_x - width / 2)                    top = int(center_y - height / 2)                    class_ids.append(class_id)                    confidences.append(float(confidence))                    boxes.append([left, top, width, height])        # 削除具有较低置信度的冗余重叠框        indices = cv2.dnn.NMSBoxes(boxes, confidences, self.conf_threshold,                                   self.nms_threshold)        for i in indices:            i = i[0]            box = boxes[i]            left = box[0]            top = box[1]            width = box[2]            height = box[3]            self.draw_pred(image, class_ids[i], confidences[i], left, top,                           left + width, top + height)    def __call__(self, image, output_file):        if isinstance(image, str):            image = cv2.imread(image, cv2.IMREAD_COLOR)        assert isinstance(image, np.ndarray), \            "传入的参数错误,应当是图片文件名或者使用OpenCV读取的图片"        # 从图片新建一个4D blob        blob = cv2.dnn.blobFromImage(image,                                     1 / 255,                                     (self.inp_width, self.inp_height),                                     [0, 0, 0],                                     1,                                     crop=False)        self.net.setInput(blob)        # 进行识别        outs = self.net.forward(self.get_outputs_names(self.net))        # 移除低置信度的识别结果        self.post_process(image, outs)        t, _ = self.net.getPerfProfile()        print('Inference time: %.2f ms' %              (t * 1000.0 / cv2.getTickFrequency()))        # 将识别结果保存到一张图片中        cv2.imwrite(output_file, image.astype(np.uint8))net = OpenCVDarknet("./yolov4.cfg", "./yolov4.weights", "coco.names")net("test.jpg", "result.jpg")

    这个代码主干是我从别处抄的,源网页的下载代码功能在我这不好使,并且他的代码在我这显示出来的时候很乱,甚至完全没有缩进,我一点一点根据他的意思自己整理的缩进

python输出graphml格式的图 如何用python输出jpg_c 如何确定一张jpg的宽高_02

。可能是我这网络环境不行,如果读者有幸能够加载代码格式的话则可以直接检视原文,不用看我这个简化版的。

    下面进行一下简单讲解。此处我使用的是YOLO V3,V4我也试成功了,但是需要OpenCV比较新的版本才能跑起来,如果读者还没用上最新版本,可以更新OpenCV或者用YOLO V3,用得到的下载地址我会统一放在文章末尾(我给的是官方的连结,比较推荐的方式是到搜索引擎搜一下看有没有云盘连结,这种方式更加快捷)。

    代码开篇给了四个超参数,分别是两个跟置信度有关的阈值和图片的宽高,如果有性能和准确度方面的特殊需求可以自行调整。宽高我这里设定为416,也可以设定为320提高速度,或者设定为608提高精度。

    原本代码中提供了读取摄像头或者视频的功能,但是我这里为了简单就给删去了,如果读者对OpenCV处理视频感兴趣的话我可以出一篇文章讲讲这个话题。

    具体使用起来,形如上面120行代码,初始化OpenCVDarknet类,指定必要的文件路径参数,使用时只需要指定图片的输入文件名和输出文件名就好了。这样设计的好处就是使用起来相当简单,如果你想要处理视频或者摄像头的图像,可以直接写一个对应功能的函数,将初始化的OpenCVDarknet类实例包裹进去就行了,可以做到开箱即用,非常的人性化。

python输出graphml格式的图 如何用python输出jpg_opencv c语言_03

    这是我将宽高指定为608的识别结果,如果是上面代码中的416,则数值会有差异。

YOLO V3权重下载地址:https://pjreddie.com/media/files/yolov3.weights

YOLO V3的cfg文件:https://github.com/pjreddie/darknet/blob/master/cfg/yolov3.cfg

coco.names:https://github.com/pjreddie/darknet/blob/master/data/coco.names