如何用CSharpOpenCv集成Yolov3的模型
目录
第三步、将weight文件、类别文件和cfg文件复制到C#程序的bin文件夹里
第一步,将训练好的.h5文件转给.weight文件
模型训练时采用TensorFlow + Keras框架,其参数模型输出为.h5文件,其中包含了yolo训练结果中的卷积层和池化层参数。
OpenCV库,其中深度神经网络(dnn)模块采用了DarkNet框架,该框架导入的模型为.weights文件,并依赖于.cfg文件所定义的架构。所以,如果想将前面的框架训练的模型用于OpenCV中,就需要将yolo.h5文件转换为yolo.weights文件。执行如下代码:
-
from tensorflow.keras.models import load_model
-
import configparser
-
import io
-
from collections import defaultdict
-
import numpy as np
-
from yolo import YOLO
-
-
def unique_config_sections(config_file):
-
"""Convert all config sections to have unique names.
-
-
Adds unique suffixes to config sections for compability with configparser.
-
"""
-
section_counters = defaultdict(int)
-
output_stream = io.StringIO()
-
with open(config_file) as fin:
-
for line in fin:
-
if line.startswith('['):
-
section = line.strip().strip('[]')
-
_section = section + '_' + str(section_counters[section])
-
section_counters[section] += 1
-
line = line.replace(section, _section)
-
output_stream.write(line)
-
output_stream.seek(0)
-
return output_stream
-
-
def _main():
-
-
unique_config_file = unique_config_sections(config_path)
-
cfg_parser = configparser.ConfigParser()
-
cfg_parser.read_file(unique_config_file)
-
-
# major, minor, revision=[0,2,0] seen=32013312
-
m_revision=[0,2,0]
-
seen=[32013312]
-
# convert to bytes
-
m_revision_const = np.array(m_revision,dtype=np.int32)
-
m_revision_bytes=m_revision_const.tobytes()
-
-
seen_const=np.array(seen,dtype=np.int64)
-
seen_bytes=seen_const.tobytes()
-
-
print('write revision information\n')
-
weight_file.write(m_revision_bytes)
-
weight_file.write(seen_bytes)
-
-
# conv2d and batch_normalize layers
-
b=0
-
print('start write weights\n')
-
for section in cfg_parser.sections():
-
-
#print('Parsing section {}'.format(section))
-
if section.startswith('convolutional'):
-
# get 'convolutional_'
-
num = int(section.split('_')[-1])+1
-
# get 'batch_normalize'
-
batch_normalize = 'batch_normalize' in cfg_parser[section]
-
# if batch_normalize write it three times and activation='leaky'
-
if batch_normalize:
-
# from batch_normalization layer extract bn_weight_list
-
batch_weight_name = 'batch_normalization_' + str(num-b)
-
bn_weight_list_layer=model.get_layer(batch_weight_name)
-
bn_weight_list =bn_weight_list_layer.get_weights()
-
-
# from bn_weight_list extract bn_weight and con_bias
-
conv_bias = bn_weight_list[1]
-
bn_weight = [bn_weight_list[0], bn_weight_list[2], bn_weight_list[3]]
-
-
# from conv2d layer extract conv_weight
-
conv2d_weight_name = 'conv2d_' + str(num)
-
# print conv2d_weight_name
-
print(conv2d_weight_name,'\n')
-
print(batch_weight_name, '\n')
-
conv2d_weight_name_layer=model.get_layer(conv2d_weight_name)
-
# list[ndarray]
-
conv_weight = conv2d_weight_name_layer.get_weights()
-
conv_weight=conv_weight[0]
-
conv_weight = np.transpose(conv_weight, [3, 2, 0, 1])
-
bias_weight = np.array(conv_bias,dtype=np.float32)
-
bytes_bias_weight=bias_weight.tobytes()
-
weight_file.write(bytes_bias_weight)
-
print(bias_weight.shape,'\n')
-
-
# convert bn_weight to bytes then write to file
-
bn_weight_array=np.array(bn_weight,dtype=np.float32)
-
bytes_bn_weight=bn_weight_array.tobytes()
-
weight_file.write(bytes_bn_weight)
-
print(bn_weight_array.shape,'\n')
-
-
conv_weight_array=np.array(conv_weight,dtype=np.float32)
-
bytes_conv_weight=conv_weight_array.tobytes()
-
weight_file.write(bytes_conv_weight)
-
print(conv_weight_array.shape,'\n')
-
-
# not existence batch_normalize layers, write it two times
-
else:
-
# b is disorder parameter
-
b+=1
-
# from conv2d layer extract conv_weight(include conv_bias)
-
print('\n')
-
conv2d_weight_name = 'conv2d_' + str(num)
-
print('disorder',conv2d_weight_name,'\n\n')
-
conv2d_weight_name_layer = model.get_layer(conv2d_weight_name)
-
conv_weights =conv2d_weight_name_layer.get_weights()
-
-
# extract conv_bias conv2d_weight
-
conv_bias = conv_weights[-1]
-
conv_weight = conv_weights[0]
-
conv_weight=np.array(conv_weight)
-
# transpose
-
conv_weight = np.transpose(conv_weight, [3, 2, 0, 1])
-
-
# write the file with order conv_bias、conv2d_weight
-
# conv_bias convert to bytes
-
bias_weight = np.array(conv_bias,dtype=np.float32)
-
bytes_bias_weight = bias_weight.tobytes()
-
weight_file.write(bytes_bias_weight)
-
print(bias_weight.shape)
-
# conv_weight convert to bytes
-
conv_weight_array = np.array(conv_weight,dtype=np.float32)
-
bytes_conv_weight = conv_weight_array.tobytes()
-
weight_file.write(bytes_conv_weight)
-
# pritn the shape
-
print(conv_weight_array.shape)
-
-
weight_file.close()
-
print("convert success!\n")
-
-
-
if __name__ == '__main__':
-
-
model_path = "weight/yolov3.h5" # keras yolov3 h5 model file
-
config_path = 'yolov3.cfg' # .cfg file path
-
weight_file = open('yolov3.weights', 'wb') # save darknet yolov3 weights file path
-
-
"""
-
The default keras yolov3 (https://github.com/qqwweee/keras-yolo3/blob/master/train.py)
-
after trained save with method " model.save_weights(log_dir + 'trained_weights_final.h5')"
-
it actually only saved weights, below call YOLO(modelpath) will check it's model,
-
if it without model information, then automatic load model.
-
-
"""
-
yoloobj = YOLO()
-
model = yoloobj.yolo_model
-
_main()
执行完成后就可以得到yolov3.weights文件。
第二步,修改cfg文件
打开yolov3.cfg,在里面查找 yolo(注意有3处),需要修改的地方处:
1、filters = 3 * ( 5 + classes)
2、classes = n (这个是你要训练的类的数量)
3,anchors改为训练时,聚类得到的结果。
例如:本文这里有3个类,所以filters=21,classes=2。
第三步、将weight文件、类别文件和cfg文件复制到C#程序的bin文件夹里
新建WinForm程序,在bin/Debug下新建yolov3文件夹,然后把weight文件、类别文件、cfg文件放进去
第四步、下载CSharpOpenCv
下载地址:https://github.com/shimat/opencvsharp/releases?after=4.5.1.20201226
我用的版本是4.1.0版本。
解压后,将OpenCvSharp.Blob.dll、OpenCvSharp.dll、OpenCvSharp.Extensions.dll、OpenCvSharpExtern.dll复制到Debug文件,然后引用到项目里面。
第四步、编写C#代码
先看页面
代码:
-
using System;
-
using System.Collections.Generic;
-
using System.ComponentModel;
-
using System.Data;
-
using System.Drawing;
-
using System.Linq;
-
using System.Text;
-
using System.Threading.Tasks;
-
using System.Windows.Forms;
-
using System.Threading;
-
using System.IO;
-
using OpenCvSharp;
-
using OpenCvSharp.Dnn;
-
using OpenCvSharp.Extensions;
-
-
namespace yolov4_detect
-
{
-
public partial class Form1 : Form
-
{
-
static string Cfg = "../../bin/Debug/yolov3/yolov3.cfg";
-
static string Weight = "../../bin/Debug/yolov3/yolov3.weights";
-
static string Names = "../../bin/Debug/yolov3/coco_classes.txt";
-
string[] Labels = File.ReadAllLines(Names).ToArray();
-
-
Scalar[] Colors = Enumerable.Repeat(false, 2).Select(x => Scalar.RandomColor()).ToArray();
-
Net net;
-
-
public Form1()
-
{
-
InitializeComponent();
-
net = CvDnn.ReadNetFromDarknet(Cfg, Weight);
-
-
}
-
private Mat imagein;
-
private Mat imageout;
-
private void Form1_Load(object sender, EventArgs e)
-
{
-
imagein = new Mat();
-
imageout = new Mat();
-
imagein = Cv2.ImRead(@"yolov3/aircraft_8.jpg");
-
pictureBox2.Image = imagein.ToBitmap();
-
}
-
private void button1_Click(object sender, EventArgs e)
-
{
-
-
imageout = yolov3_model(imagein);
-
pictureBox1.Image = imageout.ToBitmap();
-
}
-
-
-
private Mat yolov3_model(Mat imgSrc)
-
{
-
Mat org = new Mat();
-
org = imgSrc;
-
-
const float threshold = 0.5f; //for confidence
-
const float nmsThreshold = 0.3f; //threshold for nms
-
var blob = CvDnn.BlobFromImage(org, 1.0 / 255, new OpenCvSharp.Size(416, 416), new Scalar(), true, false);
-
net.SetInput(blob);
-
var outNames = net.GetUnconnectedOutLayersNames();
-
var outs = outNames.Select(_ => new Mat()).ToArray();
-
net.Forward(outs, outNames);
-
org = GetResult(outs, org, threshold, nmsThreshold);
-
-
return org;
-
}
-
private Mat GetResult(IEnumerable<Mat> output, Mat image, float threshold, float nmsThreshold, bool nms = true)
-
{
-
//for nms
-
var classIds = new List<int>();
-
var confidences = new List<float>();
-
var probabilities = new List<float>();
-
var boxes = new List<Rect2d>();
-
-
var w = image.Width;
-
var h = image.Height;
-
/*
-
YOLO3 COCO trainval output
-
0 1 : center 2 3 : w/h
-
4 : confidence 5 ~ 84 : class probability
-
*/
-
const int prefix = 5; //skip 0~4
-
-
foreach (var prob in output)
-
{
-
for (var i = 0; i < prob.Rows; i++)
-
{
-
var confidence = prob.At<float>(i, 4);
-
if (confidence > threshold)
-
{
-
//get classes probability
-
double maxVal, minVal;
-
OpenCvSharp.Point min, max;
-
Cv2.MinMaxLoc(prob.Row[i].ColRange(prefix, prob.Cols), out minVal, out maxVal, out min, out max);
-
var classes = max.X;
-
var probability = prob.At<float>(i, classes + prefix);
-
-
if (probability > threshold) //more accuracy, you can cancel it
-
{
-
//get center and width/height
-
var centerX = prob.At<float>(i, 0) * w;
-
var centerY = prob.At<float>(i, 1) * h;
-
var width = prob.At<float>(i, 2) * w;
-
var height = prob.At<float>(i, 3) * h;
-
-
if (!nms)
-
{
-
// draw result (if don't use NMSBoxes)
-
Draw(image, classes, confidence, probability, centerX, centerY, width, height);
-
continue;
-
}
-
-
//put data to list for NMSBoxes
-
classIds.Add(classes);
-
confidences.Add(confidence);
-
probabilities.Add(probability);
-
boxes.Add(new Rect2d(centerX, centerY, width, height));
-
}
-
}
-
}
-
}
-
-
if (!nms) return null;
-
-
//using non-maximum suppression to reduce overlapping low confidence box
-
int[] indices;
-
CvDnn.NMSBoxes(boxes, confidences, threshold, nmsThreshold, out indices);
-
-
-
foreach (var i in indices)
-
{
-
var box = boxes[i];
-
Draw(image, classIds[i], confidences[i], probabilities[i], box.X, box.Y, box.Width, box.Height);
-
}
-
return image;
-
}
-
private void Draw(Mat image, int classes, float confidence, float probability, double centerX, double centerY, double width, double height)
-
{
-
//var label = $"{Labels[classes]} {probability * 100:0.00}%";
-
var label = Labels[classes] + "_" + probability.ToString("f2");
-
var x1 = (centerX - width / 2) < 0 ? 0 : centerX - width / 2; //avoid left side over edge
-
//draw result
-
image.Rectangle(new OpenCvSharp.Point(x1, centerY - height / 2), new OpenCvSharp.Point(centerX + width / 2, centerY + height / 2), Colors[classes], 2);
-
int baseline = 0;
-
var textSize = Cv2.GetTextSize(label, HersheyFonts.HersheyTriplex, 0.5, 1, out baseline);
-
Cv2.Rectangle(image, new OpenCvSharp.Rect(new OpenCvSharp.Point(x1, centerY - height / 2 - textSize.Height - baseline),
-
new OpenCvSharp.Size(textSize.Width, textSize.Height + baseline)), Colors[classes], Cv2.FILLED);
-
var textColor = Cv2.Mean(Colors[classes]).Val0 < 70 ? Scalar.White : Scalar.Black;
-
Cv2.PutText(image, label, new OpenCvSharp.Point(x1, centerY - height / 2 - baseline), HersheyFonts.HersheyTriplex, 0.5, textColor);
-
}
-
-
-
-
}
-
}
运行结果:
代码下载:
https://download.csdn.net/download/hhhhhhhhhhwwwwwwwwww/13852328
文章来源: wanghao.blog.csdn.net,作者:AI浩,版权归原作者所有,如需转载,请联系作者。
原文链接:wanghao.blog.csdn.net/article/details/111772539
- 点赞
- 收藏
- 关注作者
评论(0)