├── README.md ├── onnxruntime ├── best.onnx ├── imgs │ ├── 1.jpg │ ├── 10.jpg │ ├── 11.jpg │ ├── 12.jpg │ ├── 13.jpg │ ├── 14.jpg │ ├── 15.jpg │ ├── 16.jpg │ ├── 17.jpg │ ├── 18.jpg │ ├── 19.jpg │ ├── 2.jpg │ ├── 20.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.jpg │ └── 9.jpg ├── main.cpp └── main.py └── opencv ├── best.onnx ├── imgs ├── 1.jpg ├── 10.jpg ├── 11.jpg ├── 12.jpg ├── 13.jpg ├── 14.jpg ├── 15.jpg ├── 16.jpg ├── 17.jpg ├── 18.jpg ├── 19.jpg ├── 2.jpg ├── 20.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg ├── 7.jpg ├── 8.jpg └── 9.jpg ├── main.cpp └── main.py /README.md: -------------------------------------------------------------------------------- 1 | # yolov5-detect-car_plate_corner 2 | 3 | 使用OpenCV部署yolov5检测车牌和4个角点,包含C++和Python两个版本的程序 4 | 5 | 6 | 使用ONNXRuntime部署yolov5检测车牌和4个角点,包含C++和Python两个版本的程序 7 | 8 | 程序会输出车牌的水平矩形框的左上和右下顶点的坐标(x,y),车牌的4个角点的坐标(x,y) 9 | -------------------------------------------------------------------------------- /onnxruntime/best.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/best.onnx -------------------------------------------------------------------------------- /onnxruntime/imgs/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/1.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/10.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/11.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/12.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/13.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/14.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/15.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/16.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/17.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/18.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/19.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/2.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/20.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/3.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/4.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/5.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/6.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/7.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/8.jpg -------------------------------------------------------------------------------- /onnxruntime/imgs/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/onnxruntime/imgs/9.jpg -------------------------------------------------------------------------------- /onnxruntime/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | //#include 7 | #include 8 | 9 | using namespace std; 10 | using namespace cv; 11 | using namespace Ort; 12 | 13 | struct Net_config 14 | { 15 | float confThreshold; // Confidence threshold 16 | float nmsThreshold; // Non-maximum suppression threshold 17 | float objThreshold; //Object Confidence threshold 18 | }; 19 | 20 | typedef struct corner_points 21 | { 22 | Point pt1; 23 | Point pt2; 24 | Point pt3; 25 | Point pt4; 26 | } corner_points; 27 | 28 | typedef struct BoxInfo 29 | { 30 | float x1; 31 | float y1; 32 | float x2; 33 | float y2; 34 | float score; 35 | int label; 36 | corner_points four_points; 37 | } BoxInfo; 38 | 39 | class YOLO 40 | { 41 | public: 42 | YOLO(Net_config config); 43 | void detect(Mat& frame); 44 | private: 45 | const float anchors[3][6] = { {4,5, 8,10, 13,16}, {23,29, 43,55, 73,105},{146,217, 231,300, 335,433} }; 46 | const float stride[3] = { 8.0, 16.0, 32.0 }; 47 | int inpWidth; 48 | int inpHeight; 49 | int nout; 50 | float confThreshold; 51 | float nmsThreshold; 52 | float objThreshold; 53 | 54 | Mat resize_image(Mat srcimg, int *newh, int *neww, int *top, int *left); 55 | vector input_image_; 56 | void normalize_(Mat img); 57 | void nms(vector& input_boxes); 58 | const bool keep_ratio = true; 59 | void sigmoid(Mat* out, int length); 60 | Env env = Env(ORT_LOGGING_LEVEL_ERROR, "yolov5"); 61 | Ort::Session *ort_session = nullptr; 62 | SessionOptions sessionOptions = SessionOptions(); 63 | vector input_names; 64 | vector output_names; 65 | vector> input_node_dims; // >=1 outputs 66 | vector> output_node_dims; // >=1 outputs 67 | }; 68 | 69 | static inline float sigmoid_x(float x) 70 | { 71 | return static_cast(1.f / (1.f + exp(-x))); 72 | } 73 | 74 | YOLO::YOLO(Net_config config) 75 | { 76 | this->confThreshold = config.confThreshold; 77 | this->nmsThreshold = config.nmsThreshold; 78 | this->objThreshold = config.objThreshold; 79 | 80 | string model_path = "best.onnx"; 81 | std::wstring widestr = std::wstring(model_path.begin(), model_path.end()); 82 | //OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0); 83 | sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC); 84 | ort_session = new Session(env, widestr.c_str(), sessionOptions); 85 | size_t numInputNodes = ort_session->GetInputCount(); 86 | size_t numOutputNodes = ort_session->GetOutputCount(); 87 | AllocatorWithDefaultOptions allocator; 88 | for (int i = 0; i < numInputNodes; i++) 89 | { 90 | input_names.push_back(ort_session->GetInputName(i, allocator)); 91 | Ort::TypeInfo input_type_info = ort_session->GetInputTypeInfo(i); 92 | auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo(); 93 | auto input_dims = input_tensor_info.GetShape(); 94 | input_node_dims.push_back(input_dims); 95 | } 96 | for (int i = 0; i < numOutputNodes; i++) 97 | { 98 | output_names.push_back(ort_session->GetOutputName(i, allocator)); 99 | Ort::TypeInfo output_type_info = ort_session->GetOutputTypeInfo(i); 100 | auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo(); 101 | auto output_dims = output_tensor_info.GetShape(); 102 | output_node_dims.push_back(output_dims); 103 | } 104 | this->inpHeight = input_node_dims[0][2]; 105 | this->inpWidth = input_node_dims[0][3]; 106 | this->nout = output_node_dims[0][2]; 107 | } 108 | 109 | Mat YOLO::resize_image(Mat srcimg, int *newh, int *neww, int *top, int *left) 110 | { 111 | int srch = srcimg.rows, srcw = srcimg.cols; 112 | *newh = this->inpHeight; 113 | *neww = this->inpWidth; 114 | Mat dstimg; 115 | if (this->keep_ratio && srch != srcw) { 116 | float hw_scale = (float)srch / srcw; 117 | if (hw_scale > 1) { 118 | *newh = this->inpHeight; 119 | *neww = int(this->inpWidth / hw_scale); 120 | resize(srcimg, dstimg, Size(*neww, *newh), INTER_AREA); 121 | *left = int((this->inpWidth - *neww) * 0.5); 122 | copyMakeBorder(dstimg, dstimg, 0, 0, *left, this->inpWidth - *neww - *left, BORDER_CONSTANT, 0); 123 | } 124 | else { 125 | *newh = (int)this->inpHeight * hw_scale; 126 | *neww = this->inpWidth; 127 | resize(srcimg, dstimg, Size(*neww, *newh), INTER_AREA); 128 | *top = (int)(this->inpHeight - *newh) * 0.5; 129 | copyMakeBorder(dstimg, dstimg, *top, this->inpHeight - *newh - *top, 0, 0, BORDER_CONSTANT, 0); 130 | } 131 | } 132 | else { 133 | resize(srcimg, dstimg, Size(*neww, *newh), INTER_AREA); 134 | } 135 | return dstimg; 136 | } 137 | 138 | void YOLO::normalize_(Mat img) 139 | { 140 | // img.convertTo(img, CV_32F); 141 | int row = img.rows; 142 | int col = img.cols; 143 | this->input_image_.resize(row * col * img.channels()); 144 | for (int c = 0; c < 3; c++) 145 | { 146 | for (int i = 0; i < row; i++) 147 | { 148 | for (int j = 0; j < col; j++) 149 | { 150 | float pix = img.ptr(i)[j * 3 + 2 - c]; 151 | this->input_image_[c * row * col + i * col + j] = pix / 255.0; 152 | 153 | } 154 | } 155 | } 156 | } 157 | 158 | void YOLO::sigmoid(Mat* out, int length) 159 | { 160 | float* pdata = (float*)(out->data); 161 | int i = 0; 162 | for (i = 0; i < length; i++) 163 | { 164 | pdata[i] = 1.0 / (1 + expf(-pdata[i])); 165 | } 166 | } 167 | 168 | void YOLO::nms(vector& input_boxes) 169 | { 170 | sort(input_boxes.begin(), input_boxes.end(), [](BoxInfo a, BoxInfo b) { return a.score > b.score; }); 171 | vector vArea(input_boxes.size()); 172 | for (int i = 0; i < int(input_boxes.size()); ++i) 173 | { 174 | vArea[i] = (input_boxes.at(i).x2 - input_boxes.at(i).x1 + 1) 175 | * (input_boxes.at(i).y2 - input_boxes.at(i).y1 + 1); 176 | } 177 | 178 | vector isSuppressed(input_boxes.size(), false); 179 | for (int i = 0; i < int(input_boxes.size()); ++i) 180 | { 181 | if (isSuppressed[i]) { continue; } 182 | for (int j = i + 1; j < int(input_boxes.size()); ++j) 183 | { 184 | if (isSuppressed[j]) { continue; } 185 | float xx1 = (max)(input_boxes[i].x1, input_boxes[j].x1); 186 | float yy1 = (max)(input_boxes[i].y1, input_boxes[j].y1); 187 | float xx2 = (min)(input_boxes[i].x2, input_boxes[j].x2); 188 | float yy2 = (min)(input_boxes[i].y2, input_boxes[j].y2); 189 | 190 | float w = (max)(float(0), xx2 - xx1 + 1); 191 | float h = (max)(float(0), yy2 - yy1 + 1); 192 | float inter = w * h; 193 | float ovr = inter / (vArea[i] + vArea[j] - inter); 194 | 195 | if (ovr >= this->nmsThreshold) 196 | { 197 | isSuppressed[j] = true; 198 | } 199 | } 200 | } 201 | // return post_nms; 202 | int idx_t = 0; 203 | input_boxes.erase(remove_if(input_boxes.begin(), input_boxes.end(), [&idx_t, &isSuppressed](const BoxInfo& f) { return isSuppressed[idx_t++]; }), input_boxes.end()); 204 | } 205 | 206 | void YOLO::detect(Mat& frame) 207 | { 208 | int newh = 0, neww = 0, padh = 0, padw = 0; 209 | Mat dstimg = this->resize_image(frame, &newh, &neww, &padh, &padw); 210 | this->normalize_(dstimg); 211 | array input_shape_{ 1, 3, this->inpHeight, this->inpWidth }; 212 | 213 | auto allocator_info = MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); 214 | Value input_tensor_ = Value::CreateTensor(allocator_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size()); 215 | 216 | // 开始推理 217 | vector ort_outputs = ort_session->Run(RunOptions{ nullptr }, &input_names[0], &input_tensor_, 1, output_names.data(), output_names.size()); // 开始推理 218 | const float* preds = ort_outputs[0].GetTensorMutableData(); 219 | 220 | /////generate proposals 221 | vector generate_boxes; 222 | float ratioh = (float)frame.rows / newh, ratiow = (float)frame.cols / neww; 223 | int n = 0, q = 0, i = 0, j = 0, k = 0; ///xmin,ymin,xamx,ymax,box_score,x1,y1, ... ,x4,y4,plate_score 224 | for (n = 0; n < 3; n++) ///特征图尺度 225 | { 226 | int num_grid_x = (int)(this->inpWidth / this->stride[n]); 227 | int num_grid_y = (int)(this->inpHeight / this->stride[n]); 228 | for (q = 0; q < 3; q++) ///anchor 229 | { 230 | const float anchor_w = this->anchors[n][q * 2]; 231 | const float anchor_h = this->anchors[n][q * 2 + 1]; 232 | for (i = 0; i < num_grid_y; i++) 233 | { 234 | for (j = 0; j < num_grid_x; j++) 235 | { 236 | float box_score = sigmoid_x(preds[4]); 237 | if (box_score > this->objThreshold) 238 | { 239 | float plate_score = sigmoid_x(preds[13]); 240 | //if (plate_score > this->confThreshold) 241 | //{ 242 | float cx = (sigmoid_x(preds[0]) * 2.f - 0.5f + j) * this->stride[n]; ///cx 243 | float cy = (sigmoid_x(preds[1]) * 2.f - 0.5f + i) * this->stride[n]; ///cy 244 | float w = powf(sigmoid_x(preds[2]) * 2.f, 2.f) * anchor_w; ///w 245 | float h = powf(sigmoid_x(preds[3]) * 2.f, 2.f) * anchor_h; ///h 246 | 247 | float xmin = (cx - padw - 0.5 * w)*ratiow; 248 | float ymin = (cy - padh - 0.5 * h)*ratioh; 249 | float xmax = (cx - padw + 0.5 * w)*ratiow; 250 | float ymax = (cy - padh + 0.5 * h)*ratioh; 251 | 252 | corner_points pts; 253 | k = 5; 254 | pts.pt1.x = int((preds[k] * anchor_w + j * this->stride[n] - padw) * ratiow); 255 | pts.pt1.y = int((preds[k + 1] * anchor_h + i * this->stride[n] - padh) * ratioh); 256 | k = 7; 257 | pts.pt2.x = int((preds[k] * anchor_w + j * this->stride[n] - padw) * ratiow); 258 | pts.pt2.y = int((preds[k + 1] * anchor_h + i * this->stride[n] - padh) * ratioh); 259 | k = 9; 260 | pts.pt3.x = int((preds[k] * anchor_w + j * this->stride[n] - padw) * ratiow); 261 | pts.pt3.y = int((preds[k + 1] * anchor_h + i * this->stride[n] - padh) * ratioh); 262 | k = 11; 263 | pts.pt4.x = int((preds[k] * anchor_w + j * this->stride[n] - padw) * ratiow); 264 | pts.pt4.y = int((preds[k + 1] * anchor_h + i * this->stride[n] - padh) * ratioh); 265 | 266 | generate_boxes.push_back(BoxInfo{ xmin, ymin, xmax, ymax, plate_score, 0, pts}); 267 | //} 268 | } 269 | preds += nout; 270 | } 271 | } 272 | } 273 | } 274 | 275 | nms(generate_boxes); 276 | for (size_t i = 0; i < generate_boxes.size(); ++i) 277 | { 278 | rectangle(frame, Point(int(generate_boxes[i].x1), int(generate_boxes[i].y1)), Point(int(generate_boxes[i].x2), int(generate_boxes[i].y2)), Scalar(0, 0, 255), 2); 279 | circle(frame, generate_boxes[i].four_points.pt1, 2, Scalar(0, 255, 0), -1); 280 | circle(frame, generate_boxes[i].four_points.pt2, 2, Scalar(0, 255, 0), -1); 281 | circle(frame, generate_boxes[i].four_points.pt3, 2, Scalar(0, 255, 0), -1); 282 | circle(frame, generate_boxes[i].four_points.pt4, 2, Scalar(0, 255, 0), -1); 283 | } 284 | } 285 | 286 | int main() 287 | { 288 | Net_config yolo_nets = { 0.3, 0.5, 0.3}; 289 | YOLO yolo_model(yolo_nets); 290 | string imgpath = "imgs/1.jpg"; 291 | Mat srcimg = imread(imgpath); 292 | yolo_model.detect(srcimg); 293 | 294 | static const string kWinName = "Deep learning object detection in ONNXRuntime"; 295 | namedWindow(kWinName, WINDOW_NORMAL); 296 | imshow(kWinName, srcimg); 297 | waitKey(0); 298 | destroyAllWindows(); 299 | } 300 | -------------------------------------------------------------------------------- /onnxruntime/main.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import argparse 3 | import numpy as np 4 | import onnxruntime as ort 5 | 6 | class yolov5(): 7 | def __init__(self, confThreshold=0.5, nmsThreshold=0.5, objThreshold=0.5): 8 | anchors = [[4, 5, 8, 10, 13, 16], [23, 29, 43, 55, 73, 105], [146, 217, 231, 300, 335, 433]] 9 | num_classes = 1 10 | self.nl = len(anchors) 11 | self.na = len(anchors[0]) // 2 12 | self.no = num_classes + 5 + 10 13 | self.grid = [np.zeros(1)] * self.nl 14 | self.stride = np.array([8., 16., 32.]) 15 | self.anchor_grid = np.asarray(anchors, dtype=np.float32).reshape(self.nl, -1, 2) 16 | self.inpWidth = 640 17 | self.inpHeight = 640 18 | so = ort.SessionOptions() 19 | so.log_severity_level = 3 20 | self.net = ort.InferenceSession('best_dynamic.onnx', so) 21 | self.confThreshold = confThreshold 22 | self.nmsThreshold = nmsThreshold 23 | self.objThreshold = objThreshold 24 | def enable_dynamic_hw(self, srcimg): 25 | srch,srcw = srcimg.shape[:2] 26 | if srch>srcw: 27 | newh = self.inpHeight 28 | neww = int(self.inpHeight * (srcw/srch)) 29 | # neww = self.inpWidth 30 | # newh = int(self.inpWidth * (srch/srcw)) 31 | else: 32 | neww = self.inpWidth 33 | newh = int(self.inpWidth * (srch/srcw)) 34 | img = cv2.resize(srcimg, (neww, newh)) 35 | return img, (newh, neww) 36 | def resize_image(self, srcimg, keep_ratio=True): 37 | top, left, newh, neww = 0, 0, self.inpWidth, self.inpHeight 38 | if keep_ratio and srcimg.shape[0] != srcimg.shape[1]: 39 | hw_scale = srcimg.shape[0] / srcimg.shape[1] 40 | if hw_scale > 1: 41 | newh, neww = self.inpHeight, int(self.inpWidth / hw_scale) 42 | img = cv2.resize(srcimg, (neww, newh), interpolation=cv2.INTER_AREA) 43 | left = int((self.inpWidth - neww) * 0.5) 44 | img = cv2.copyMakeBorder(img, 0, 0, left, self.inpWidth - neww - left, cv2.BORDER_CONSTANT, 45 | value=0) # add border 46 | else: 47 | newh, neww = int(self.inpHeight * hw_scale), self.inpWidth 48 | img = cv2.resize(srcimg, (neww, newh), interpolation=cv2.INTER_AREA) 49 | top = int((self.inpHeight - newh) * 0.5) 50 | img = cv2.copyMakeBorder(img, top, self.inpHeight - newh - top, 0, 0, cv2.BORDER_CONSTANT, value=0) 51 | else: 52 | img = cv2.resize(srcimg, (self.inpWidth, self.inpHeight), interpolation=cv2.INTER_AREA) 53 | return img, newh, neww, top, left 54 | def _make_grid(self, nx=20, ny=20): 55 | xv, yv = np.meshgrid(np.arange(ny), np.arange(nx)) 56 | return np.stack((xv, yv), 2).reshape((-1, 2)).astype(np.float32) 57 | def preprocess(self, img): 58 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 59 | img = img.astype(np.float32) / 255.0 60 | return img 61 | def postprocess(self, frame, outs, padsize): 62 | frameHeight = frame.shape[0] 63 | frameWidth = frame.shape[1] 64 | newh, neww, padh, padw = padsize 65 | ratioh, ratiow = frameHeight / newh, frameWidth / neww 66 | # Scan through all the bounding boxes output from the network and keep only the 67 | # ones with high confidence scores. Assign the box's class label as the class with the highest score. 68 | 69 | confidences = [] 70 | boxes = [] 71 | landmarks = [] 72 | for detection in outs: 73 | confidence = detection[13] 74 | # if confidence > self.confThreshold and detection[4] > self.objThreshold: 75 | if detection[4] > self.objThreshold: 76 | center_x = int((detection[0] - padw) * ratiow) 77 | center_y = int((detection[1] - padh) * ratioh) 78 | width = int(detection[2] * ratiow) 79 | height = int(detection[3] * ratioh) 80 | left = int(center_x - width / 2) 81 | top = int(center_y - height / 2) 82 | 83 | confidences.append(float(confidence)) 84 | boxes.append([left, top, width, height]) 85 | landmark = (detection[5:13] - np.tile(np.float32([padw, padh]), 4)) * np.tile(np.float32([ratiow, ratioh]), 4) 86 | landmarks.append(landmark.astype(np.int32)) 87 | # Perform non maximum suppression to eliminate redundant overlapping boxes with 88 | # lower confidences. 89 | indices = cv2.dnn.NMSBoxes(boxes, confidences, self.confThreshold, self.nmsThreshold) 90 | for i in indices: 91 | i = i[0] 92 | box = boxes[i] 93 | left = box[0] 94 | top = box[1] 95 | width = box[2] 96 | height = box[3] 97 | landmark = landmarks[i] 98 | frame = self.drawPred(frame, confidences[i], left, top, left + width, top + height, landmark) 99 | return frame 100 | 101 | def drawPred(self, frame, conf, left, top, right, bottom, landmark): 102 | # Draw a bounding box. 103 | cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), thickness=2) 104 | # label = '%.2f' % conf 105 | # Display the label at the top of the bounding box 106 | # labelSize, baseLine = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1) 107 | # top = max(top, labelSize[1]) 108 | # cv2.putText(frame, label, (left, top - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), thickness=2) 109 | for i in range(4): 110 | cv2.circle(frame, (landmark[i * 2], landmark[i * 2 + 1]), 2, (0, 255, 0), thickness=-1) 111 | return frame 112 | 113 | def detect(self, srcimg): 114 | img, newh, neww, top, left = self.resize_image(srcimg) 115 | img = self.preprocess(img) 116 | blob = np.expand_dims(np.transpose(img, (2, 0, 1)), axis=0) 117 | outs = self.net.run(None, {self.net.get_inputs()[0].name: blob})[0].squeeze(axis=0) 118 | 119 | # inference output 120 | outs[..., [0, 1, 2, 3, 4, 13]] = 1 / (1 + np.exp(-outs[..., [0, 1, 2, 3, 4, 13]])) ###sigmoid 121 | row_ind = 0 122 | for i in range(self.nl): 123 | h, w = int(self.inpHeight / self.stride[i]), int(self.inpWidth / self.stride[i]) 124 | length = int(self.na * h * w) 125 | if self.grid[i].shape[2:4] != (h, w): 126 | self.grid[i] = self._make_grid(w, h) 127 | 128 | g_i = np.tile(self.grid[i], (self.na, 1)) 129 | a_g_i = np.repeat(self.anchor_grid[i], h * w, axis=0) 130 | outs[row_ind:row_ind + length, 0:2] = (outs[row_ind:row_ind + length, 0:2] * 2. - 0.5 + g_i) * int( 131 | self.stride[i]) 132 | outs[row_ind:row_ind + length, 2:4] = (outs[row_ind:row_ind + length, 2:4] * 2) ** 2 * a_g_i 133 | 134 | outs[row_ind:row_ind + length, 5:7] = outs[row_ind:row_ind + length, 5:7] * a_g_i + g_i * int( 135 | self.stride[i]) # landmark x1 y1 136 | outs[row_ind:row_ind + length, 7:9] = outs[row_ind:row_ind + length, 7:9] * a_g_i + g_i * int( 137 | self.stride[i]) # landmark x2 y2 138 | outs[row_ind:row_ind + length, 9:11] = outs[row_ind:row_ind + length, 9:11] * a_g_i + g_i * int( 139 | self.stride[i]) # landmark x3 y3 140 | outs[row_ind:row_ind + length, 11:13] = outs[row_ind:row_ind + length, 11:13] * a_g_i + g_i * int( 141 | self.stride[i]) # landmark x4 y4 142 | row_ind += length 143 | srcimg = self.postprocess(srcimg, outs, padsize=(newh, neww, top, left)) 144 | return srcimg 145 | 146 | if __name__ == "__main__": 147 | parser = argparse.ArgumentParser() 148 | parser.add_argument("--imgpath", type=str, default='imgs/1.jpg', help="image path") 149 | parser.add_argument('--confThreshold', default=0.3, type=float, help='class confidence') 150 | parser.add_argument('--nmsThreshold', default=0.5, type=float, help='nms iou thresh') 151 | parser.add_argument('--objThreshold', default=0.3, type=float, help='object confidence') 152 | args = parser.parse_args() 153 | 154 | yolonet = yolov5(confThreshold=args.confThreshold, nmsThreshold=args.nmsThreshold, 155 | objThreshold=args.objThreshold) 156 | srcimg = cv2.imread(args.imgpath) 157 | srcimg = yolonet.detect(srcimg) 158 | 159 | winName = 'Deep learning object detection in ONNXRuntime' 160 | cv2.namedWindow(winName, 0) 161 | cv2.imshow(winName, srcimg) 162 | cv2.waitKey(0) 163 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /opencv/best.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/best.onnx -------------------------------------------------------------------------------- /opencv/imgs/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/1.jpg -------------------------------------------------------------------------------- /opencv/imgs/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/10.jpg -------------------------------------------------------------------------------- /opencv/imgs/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/11.jpg -------------------------------------------------------------------------------- /opencv/imgs/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/12.jpg -------------------------------------------------------------------------------- /opencv/imgs/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/13.jpg -------------------------------------------------------------------------------- /opencv/imgs/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/14.jpg -------------------------------------------------------------------------------- /opencv/imgs/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/15.jpg -------------------------------------------------------------------------------- /opencv/imgs/16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/16.jpg -------------------------------------------------------------------------------- /opencv/imgs/17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/17.jpg -------------------------------------------------------------------------------- /opencv/imgs/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/18.jpg -------------------------------------------------------------------------------- /opencv/imgs/19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/19.jpg -------------------------------------------------------------------------------- /opencv/imgs/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/2.jpg -------------------------------------------------------------------------------- /opencv/imgs/20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/20.jpg -------------------------------------------------------------------------------- /opencv/imgs/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/3.jpg -------------------------------------------------------------------------------- /opencv/imgs/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/4.jpg -------------------------------------------------------------------------------- /opencv/imgs/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/5.jpg -------------------------------------------------------------------------------- /opencv/imgs/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/6.jpg -------------------------------------------------------------------------------- /opencv/imgs/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/7.jpg -------------------------------------------------------------------------------- /opencv/imgs/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/8.jpg -------------------------------------------------------------------------------- /opencv/imgs/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/imgs/9.jpg -------------------------------------------------------------------------------- /opencv/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpc203/yolov5-detect-car_plate_corner/06674273526a48405dab812050051d479299af84/opencv/main.cpp -------------------------------------------------------------------------------- /opencv/main.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import argparse 3 | import numpy as np 4 | 5 | class yolov5(): 6 | def __init__(self, confThreshold=0.5, nmsThreshold=0.5, objThreshold=0.5): 7 | anchors = [[4, 5, 8, 10, 13, 16], [23, 29, 43, 55, 73, 105], [146, 217, 231, 300, 335, 433]] 8 | num_classes = 1 9 | self.nl = len(anchors) 10 | self.na = len(anchors[0]) // 2 11 | self.no = num_classes + 5 + 10 12 | self.grid = [np.zeros(1)] * self.nl 13 | self.stride = np.array([8., 16., 32.]) 14 | self.anchor_grid = np.asarray(anchors, dtype=np.float32).reshape(self.nl, -1, 2) 15 | self.inpWidth = 640 16 | self.inpHeight = 640 17 | self.net = cv2.dnn.readNet('best.onnx') 18 | self.confThreshold = confThreshold 19 | self.nmsThreshold = nmsThreshold 20 | self.objThreshold = objThreshold 21 | def enable_dynamic_hw(self, srcimg): 22 | srch,srcw = srcimg.shape[:2] 23 | if srch>srcw: 24 | newh = self.inpHeight 25 | neww = int(self.inpHeight * (srcw/srch)) 26 | # neww = self.inpWidth 27 | # newh = int(self.inpWidth * (srch/srcw)) 28 | else: 29 | neww = self.inpWidth 30 | newh = int(self.inpWidth * (srch/srcw)) 31 | img = cv2.resize(srcimg, (neww, newh)) 32 | return img, (newh, neww) 33 | def resize_image(self, srcimg, keep_ratio=True): 34 | top, left, newh, neww = 0, 0, self.inpWidth, self.inpHeight 35 | if keep_ratio and srcimg.shape[0] != srcimg.shape[1]: 36 | hw_scale = srcimg.shape[0] / srcimg.shape[1] 37 | if hw_scale > 1: 38 | newh, neww = self.inpHeight, int(self.inpWidth / hw_scale) 39 | img = cv2.resize(srcimg, (neww, newh), interpolation=cv2.INTER_AREA) 40 | left = int((self.inpWidth - neww) * 0.5) 41 | img = cv2.copyMakeBorder(img, 0, 0, left, self.inpWidth - neww - left, cv2.BORDER_CONSTANT, 42 | value=0) # add border 43 | else: 44 | newh, neww = int(self.inpHeight * hw_scale), self.inpWidth 45 | img = cv2.resize(srcimg, (neww, newh), interpolation=cv2.INTER_AREA) 46 | top = int((self.inpHeight - newh) * 0.5) 47 | img = cv2.copyMakeBorder(img, top, self.inpHeight - newh - top, 0, 0, cv2.BORDER_CONSTANT, value=0) 48 | else: 49 | img = cv2.resize(srcimg, (self.inpWidth, self.inpHeight), interpolation=cv2.INTER_AREA) 50 | return img, newh, neww, top, left 51 | def _make_grid(self, nx=20, ny=20): 52 | xv, yv = np.meshgrid(np.arange(ny), np.arange(nx)) 53 | return np.stack((xv, yv), 2).reshape((-1, 2)).astype(np.float32) 54 | def preprocess(self, img): 55 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 56 | img = img.astype(np.float32) / 255.0 57 | return img 58 | def postprocess(self, frame, outs, padsize=None): 59 | frameHeight = frame.shape[0] 60 | frameWidth = frame.shape[1] 61 | newh, neww, padh, padw = padsize 62 | ratioh, ratiow = frameHeight / newh, frameWidth / neww 63 | # Scan through all the bounding boxes output from the network and keep only the 64 | # ones with high confidence scores. Assign the box's class label as the class with the highest score. 65 | 66 | confidences = [] 67 | boxes = [] 68 | landmarks = [] 69 | for detection in outs: 70 | confidence = detection[13] 71 | # if confidence > self.confThreshold and detection[4] > self.objThreshold: 72 | if detection[4] > self.objThreshold: 73 | center_x = int((detection[0] - padw) * ratiow) 74 | center_y = int((detection[1] - padh) * ratioh) 75 | width = int(detection[2] * ratiow) 76 | height = int(detection[3] * ratioh) 77 | left = int(center_x - width / 2) 78 | top = int(center_y - height / 2) 79 | 80 | confidences.append(float(confidence)) 81 | boxes.append([left, top, width, height]) 82 | landmark = (detection[5:13] - np.tile(np.float32([padw, padh]), 4)) * np.tile(np.float32([ratiow, ratioh]), 4) 83 | landmarks.append(landmark.astype(np.int32)) 84 | # Perform non maximum suppression to eliminate redundant overlapping boxes with 85 | # lower confidences. 86 | indices = cv2.dnn.NMSBoxes(boxes, confidences, self.confThreshold, self.nmsThreshold) 87 | for i in indices: 88 | i = i[0] 89 | box = boxes[i] 90 | left = box[0] 91 | top = box[1] 92 | width = box[2] 93 | height = box[3] 94 | landmark = landmarks[i] 95 | frame = self.drawPred(frame, confidences[i], left, top, left + width, top + height, landmark) 96 | return frame 97 | 98 | def drawPred(self, frame, conf, left, top, right, bottom, landmark): 99 | # Draw a bounding box. 100 | cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), thickness=2) 101 | # label = '%.2f' % conf 102 | # Display the label at the top of the bounding box 103 | # labelSize, baseLine = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1) 104 | # top = max(top, labelSize[1]) 105 | # cv2.putText(frame, label, (left, top - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), thickness=2) 106 | for i in range(4): 107 | cv2.circle(frame, (landmark[i * 2], landmark[i * 2 + 1]), 2, (0, 255, 0), thickness=-1) 108 | return frame 109 | 110 | def detect(self, srcimg): 111 | # blob = cv2.dnn.blobFromImage(srcimg, 1 / 255.0, (self.inpWidth, self.inpHeight), [0, 0, 0], swapRB=True, crop=False) 112 | img, newh, neww, top, left = self.resize_image(srcimg) 113 | # blob = cv2.dnn.blobFromImage(self.preprocess(img)) 114 | blob = cv2.dnn.blobFromImage(img, scalefactor=1 / 255.0, swapRB=True) 115 | # img, dynamic_hw = self.enable_dynamic_hw(srcimg) 116 | # newh, neww, top, left = dynamic_hw[0], dynamic_hw[1], 0, 0 117 | # blob = cv2.dnn.blobFromImage(self.preprocess(img)) 118 | 119 | # Sets the input to the network 120 | self.net.setInput(blob) 121 | 122 | # Runs the forward pass to get output of the output layers 123 | outs = self.net.forward(self.net.getUnconnectedOutLayersNames())[0].squeeze(axis=0) 124 | 125 | # inference output 126 | outs[..., [0, 1, 2, 3, 4, 13]] = 1 / (1 + np.exp(-outs[..., [0, 1, 2, 3, 4, 13]])) ###sigmoid 127 | row_ind = 0 128 | for i in range(self.nl): 129 | h, w = int(self.inpHeight / self.stride[i]), int(self.inpWidth / self.stride[i]) 130 | length = int(self.na * h * w) 131 | if self.grid[i].shape[2:4] != (h, w): 132 | self.grid[i] = self._make_grid(w, h) 133 | 134 | g_i = np.tile(self.grid[i], (self.na, 1)) 135 | a_g_i = np.repeat(self.anchor_grid[i], h * w, axis=0) 136 | outs[row_ind:row_ind + length, 0:2] = (outs[row_ind:row_ind + length, 0:2] * 2. - 0.5 + g_i) * int( 137 | self.stride[i]) 138 | outs[row_ind:row_ind + length, 2:4] = (outs[row_ind:row_ind + length, 2:4] * 2) ** 2 * a_g_i 139 | 140 | outs[row_ind:row_ind + length, 5:7] = outs[row_ind:row_ind + length, 5:7] * a_g_i + g_i * int( 141 | self.stride[i]) # landmark x1 y1 142 | outs[row_ind:row_ind + length, 7:9] = outs[row_ind:row_ind + length, 7:9] * a_g_i + g_i * int( 143 | self.stride[i]) # landmark x2 y2 144 | outs[row_ind:row_ind + length, 9:11] = outs[row_ind:row_ind + length, 9:11] * a_g_i + g_i * int( 145 | self.stride[i]) # landmark x3 y3 146 | outs[row_ind:row_ind + length, 11:13] = outs[row_ind:row_ind + length, 11:13] * a_g_i + g_i * int( 147 | self.stride[i]) # landmark x4 y4 148 | row_ind += length 149 | srcimg = self.postprocess(srcimg, outs, padsize=(newh, neww, top, left)) 150 | return srcimg 151 | 152 | if __name__ == "__main__": 153 | parser = argparse.ArgumentParser() 154 | parser.add_argument("--imgpath", type=str, default='imgs/1.jpg', help="image path") 155 | parser.add_argument('--confThreshold', default=0.3, type=float, help='class confidence') 156 | parser.add_argument('--nmsThreshold', default=0.5, type=float, help='nms iou thresh') 157 | parser.add_argument('--objThreshold', default=0.3, type=float, help='object confidence') 158 | args = parser.parse_args() 159 | 160 | yolonet = yolov5(confThreshold=args.confThreshold, nmsThreshold=args.nmsThreshold, 161 | objThreshold=args.objThreshold) 162 | srcimg = cv2.imread(args.imgpath) 163 | srcimg = yolonet.detect(srcimg) 164 | 165 | winName = 'Deep learning object detection in OpenCV' 166 | cv2.namedWindow(winName, 0) 167 | cv2.imshow(winName, srcimg) 168 | cv2.waitKey(0) 169 | cv2.destroyAllWindows() --------------------------------------------------------------------------------