Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
Kayzwer committed Feb 27, 2024
1 parent 1793a0a commit 85a68bf
Show file tree
Hide file tree
Showing 12 changed files with 959 additions and 973 deletions.
20 changes: 10 additions & 10 deletions Extentions/RectangleExtensions.cs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace YOLO.Extentions
{
public static class RectangleExtensions
{
public static float Area(this RectangleF source)
{
return source.Width * source.Height;
}
}
}
namespace YOLO.Extentions
{
public static class RectangleExtensions
{
public static float Area(this RectangleF source)
{
return source.Width * source.Height;
}
}
}
308 changes: 154 additions & 154 deletions Extentions/Utils.cs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,154 +1,154 @@
using Microsoft.ML.OnnxRuntime.Tensors;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;


namespace YOLO.Extentions
{
public static class Utils
{
public static Bitmap ResizeImage(Image image, int target_width, int target_height)
{
Bitmap output = new(target_width, target_height, image.PixelFormat);
var (w, h) = ((float)image.Width, (float)image.Height); // image width and height
var (xRatio, yRatio) = (target_width / w, target_height / h); // x, y ratios
float ratio = Math.Min(xRatio, yRatio); // ratio = resized / original
var (width, height) = ((int)(w * ratio), (int)(h * ratio)); // roi width and height
var (x, y) = ((int)((target_width * 0.5f) - (width * 0.5f)), (int)((target_height * 0.5f) - (height * 0.5f))); // roi x and y coordinates
using Graphics graphics = Graphics.FromImage(output);
graphics.Clear(Color.FromArgb(0, 0, 0, 0)); // clear canvas
graphics.SmoothingMode = SmoothingMode.None; // no smoothing
graphics.InterpolationMode = InterpolationMode.NearestNeighbor; // nn interpolation
graphics.PixelOffsetMode = PixelOffsetMode.Half; // half pixel offset
graphics.DrawImage(image, new Rectangle(x, y, width, height)); // draw scaled
return output;
}

//https://github.com/ivilson/Yolov7net/issues/17
public static Tensor<float> ExtractPixels2(Bitmap bitmap)
{
int pixelCount = bitmap.Width * bitmap.Height;
Rectangle rectangle = new(0, 0, bitmap.Width, bitmap.Height);
DenseTensor<float> tensor = new(new[] { 1, 3, bitmap.Height, bitmap.Width });
Span<byte> data;

BitmapData bitmapData;
if (bitmap.PixelFormat == PixelFormat.Format24bppRgb && bitmap.Width % 4 == 0)
{
bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

unsafe
{
data = new Span<byte>((void*)bitmapData.Scan0, bitmapData.Height * bitmapData.Stride);
}

ExtractPixelsRgb(tensor, data, pixelCount);
}
else
{
// force convert to 32 bit PArgb
bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);

unsafe
{
data = new Span<byte>((void*)bitmapData.Scan0, bitmapData.Height * bitmapData.Stride);
}

ExtractPixelsArgb(tensor, data, pixelCount);
}

bitmap.UnlockBits(bitmapData);

return tensor;
}

public static void ExtractPixelsArgb(DenseTensor<float> tensor, Span<byte> data, int pixelCount)
{
Span<float> spanR = tensor.Buffer.Span;
Span<float> spanG = spanR[pixelCount..];
Span<float> spanB = spanG[pixelCount..];

int sidx = 0;
for (int i = 0; i < pixelCount; i++)
{
spanR[i] = data[sidx + 2] * 0.0039215686274509803921568627451f;
spanG[i] = data[sidx + 1] * 0.0039215686274509803921568627451f;
spanB[i] = data[sidx] * 0.0039215686274509803921568627451f;
sidx += 4;
}
}

public static void ExtractPixelsRgb(DenseTensor<float> tensor, Span<byte> data, int pixelCount)
{
Span<float> spanR = tensor.Buffer.Span;
Span<float> spanG = spanR[pixelCount..];
Span<float> spanB = spanG[pixelCount..];

int sidx = 0;
for (int i = 0; i < pixelCount; i++)
{
spanR[i] = data[sidx + 2] * 0.0039215686274509803921568627451f;
spanG[i] = data[sidx + 1] * 0.0039215686274509803921568627451f;
spanB[i] = data[sidx] * 0.0039215686274509803921568627451f;
sidx += 3;
}
}

public static float Clamp(float value, float min, float max)
{
return value < min ? min : value > max ? max : value;
}

public static Image DrawBoundingBox(Image image, List<YoloPrediction> predictions, int bounding_box_thickness, int font_size)
{
using Graphics graphics = Graphics.FromImage(image);
for (int i = 0; i < predictions.Count; i++)
{
float score = (float)Math.Round(predictions[i].Score, 2);
graphics.DrawRectangles(new(predictions[i].Label.Color, bounding_box_thickness), new[] { predictions[i].Rectangle });
graphics.DrawString($"{predictions[i].Label.Name} ({score})",
new("Consolas", font_size, GraphicsUnit.Pixel), new SolidBrush(predictions[i].Label.Color),
new PointF(predictions[i].Rectangle.X, predictions[i].Rectangle.Y));
}
return image;
}

public static Image DrawRotatedBoundingBox(Image image, List<OBBPrediction> predictions, int bounding_box_thickness, int font_size)
{
using Graphics graphics = Graphics.FromImage(image);
for (int i = 0; i < predictions.Count; i++)
{
float score = (float)Math.Round(predictions[i].Score, 2);
graphics.DrawPolygon(new(predictions[i].Label.Color, bounding_box_thickness), GetRotatedPoints(predictions[i]));
graphics.DrawString($"{predictions[i].Label.Name} ({score})",
new("Consolas", font_size, GraphicsUnit.Pixel), new SolidBrush(predictions[i].Label.Color),
new PointF(predictions[i].Rectangle.X, predictions[i].Rectangle.Y));
}
return image;
}

public static PointF[] GetRotatedPoints(OBBPrediction prediction)
{
PointF[] points = new PointF[]
{
new(prediction.Rectangle.X, prediction.Rectangle.Y),
new(prediction.Rectangle.X + prediction.Rectangle.Width, prediction.Rectangle.Y),
new(prediction.Rectangle.X + prediction.Rectangle.Width, prediction.Rectangle.Y + prediction.Rectangle.Height),
new(prediction.Rectangle.X, prediction.Rectangle.Y + prediction.Rectangle.Height)
};
OpenCvSharp.Point2f middle = new(prediction.Rectangle.X + prediction.Rectangle.Width * .5f,
prediction.Rectangle.Y + prediction.Rectangle.Height * .5f);
float cos_angle = (float)Math.Cos(prediction.Angle);
float sin_angle = (float)Math.Sin(prediction.Angle);
for (int i = 0; i < 4; i++)
{
float offset_x = middle.X - points[i].X;
float offset_y = middle.Y - points[i].Y;
float rotated_x = offset_x * cos_angle - offset_y * sin_angle;
float rotated_y = offset_x * sin_angle + offset_y * cos_angle;
points[i] = new(middle.X + rotated_x, middle.Y + rotated_y);
}
return points;
}
}
}
using Microsoft.ML.OnnxRuntime.Tensors;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;


namespace YOLO.Extentions
{
public static class Utils
{
public static Bitmap ResizeImage(Image image, int target_width, int target_height)
{
Bitmap output = new(target_width, target_height, image.PixelFormat);
var (w, h) = ((float)image.Width, (float)image.Height); // image width and height
var (xRatio, yRatio) = (target_width / w, target_height / h); // x, y ratios
float ratio = Math.Min(xRatio, yRatio); // ratio = resized / original
var (width, height) = ((int)(w * ratio), (int)(h * ratio)); // roi width and height
var (x, y) = ((int)((target_width * 0.5f) - (width * 0.5f)), (int)((target_height * 0.5f) - (height * 0.5f))); // roi x and y coordinates
using Graphics graphics = Graphics.FromImage(output);
graphics.Clear(Color.FromArgb(0, 0, 0, 0)); // clear canvas
graphics.SmoothingMode = SmoothingMode.None; // no smoothing
graphics.InterpolationMode = InterpolationMode.NearestNeighbor; // nn interpolation
graphics.PixelOffsetMode = PixelOffsetMode.Half; // half pixel offset
graphics.DrawImage(image, new Rectangle(x, y, width, height)); // draw scaled
return output;
}

//https://github.com/ivilson/Yolov7net/issues/17
public static Tensor<float> ExtractPixels2(Bitmap bitmap)
{
int pixelCount = bitmap.Width * bitmap.Height;
Rectangle rectangle = new(0, 0, bitmap.Width, bitmap.Height);
DenseTensor<float> tensor = new(new[] { 1, 3, bitmap.Height, bitmap.Width });
Span<byte> data;

BitmapData bitmapData;
if (bitmap.PixelFormat == PixelFormat.Format24bppRgb && bitmap.Width % 4 == 0)
{
bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

unsafe
{
data = new Span<byte>((void*)bitmapData.Scan0, bitmapData.Height * bitmapData.Stride);
}

ExtractPixelsRgb(tensor, data, pixelCount);
}
else
{
// force convert to 32 bit PArgb
bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);

unsafe
{
data = new Span<byte>((void*)bitmapData.Scan0, bitmapData.Height * bitmapData.Stride);
}

ExtractPixelsArgb(tensor, data, pixelCount);
}

bitmap.UnlockBits(bitmapData);

return tensor;
}

public static void ExtractPixelsArgb(DenseTensor<float> tensor, Span<byte> data, int pixelCount)
{
Span<float> spanR = tensor.Buffer.Span;
Span<float> spanG = spanR[pixelCount..];
Span<float> spanB = spanG[pixelCount..];

int sidx = 0;
for (int i = 0; i < pixelCount; i++)
{
spanR[i] = data[sidx + 2] * 0.0039215686274509803921568627451f;
spanG[i] = data[sidx + 1] * 0.0039215686274509803921568627451f;
spanB[i] = data[sidx] * 0.0039215686274509803921568627451f;
sidx += 4;
}
}

public static void ExtractPixelsRgb(DenseTensor<float> tensor, Span<byte> data, int pixelCount)
{
Span<float> spanR = tensor.Buffer.Span;
Span<float> spanG = spanR[pixelCount..];
Span<float> spanB = spanG[pixelCount..];

int sidx = 0;
for (int i = 0; i < pixelCount; i++)
{
spanR[i] = data[sidx + 2] * 0.0039215686274509803921568627451f;
spanG[i] = data[sidx + 1] * 0.0039215686274509803921568627451f;
spanB[i] = data[sidx] * 0.0039215686274509803921568627451f;
sidx += 3;
}
}

public static float Clamp(float value, float min, float max)
{
return value < min ? min : value > max ? max : value;
}

public static Image DrawBoundingBox(Image image, List<YoloPrediction> predictions, int bounding_box_thickness, int font_size)
{
using Graphics graphics = Graphics.FromImage(image);
for (int i = 0; i < predictions.Count; i++)
{
float score = (float)Math.Round(predictions[i].Score, 2);
graphics.DrawRectangles(new(predictions[i].Label.Color, bounding_box_thickness), new[] { predictions[i].Rectangle });
graphics.DrawString($"{predictions[i].Label.Name} ({score})",
new("Consolas", font_size, GraphicsUnit.Pixel), new SolidBrush(predictions[i].Label.Color),
new PointF(predictions[i].Rectangle.X, predictions[i].Rectangle.Y));
}
return image;
}

public static Image DrawRotatedBoundingBox(Image image, List<OBBPrediction> predictions, int bounding_box_thickness, int font_size)
{
using Graphics graphics = Graphics.FromImage(image);
for (int i = 0; i < predictions.Count; i++)
{
float score = (float)Math.Round(predictions[i].Score, 2);
graphics.DrawPolygon(new(predictions[i].Label.Color, bounding_box_thickness), GetRotatedPoints(predictions[i]));
graphics.DrawString($"{predictions[i].Label.Name} ({score})",
new("Consolas", font_size, GraphicsUnit.Pixel), new SolidBrush(predictions[i].Label.Color),
new PointF(predictions[i].Rectangle.X, predictions[i].Rectangle.Y));
}
return image;
}

public static PointF[] GetRotatedPoints(OBBPrediction prediction)
{
PointF[] points = new PointF[]
{
new(prediction.Rectangle.X, prediction.Rectangle.Y),
new(prediction.Rectangle.X + prediction.Rectangle.Width, prediction.Rectangle.Y),
new(prediction.Rectangle.X + prediction.Rectangle.Width, prediction.Rectangle.Y + prediction.Rectangle.Height),
new(prediction.Rectangle.X, prediction.Rectangle.Y + prediction.Rectangle.Height)
};
OpenCvSharp.Point2f middle = new(prediction.Rectangle.X + prediction.Rectangle.Width * .5f,
prediction.Rectangle.Y + prediction.Rectangle.Height * .5f);
float cos_angle = (float)Math.Cos(prediction.Angle);
float sin_angle = (float)Math.Sin(prediction.Angle);
for (int i = 0; i < 4; i++)
{
float offset_x = middle.X - points[i].X;
float offset_y = middle.Y - points[i].Y;
float rotated_x = offset_x * cos_angle - offset_y * sin_angle;
float rotated_y = offset_x * sin_angle + offset_y * cos_angle;
points[i] = new(middle.X + rotated_x, middle.Y + rotated_y);
}
return points;
}
}
}
22 changes: 11 additions & 11 deletions Models/YoloModel.cs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace YOLO.Models
{
public class YoloModel
{
public int Dimensions { get; set; } //yolov7 包含nms 的模型不需要此参数

public string[] Outputs { get; set; }

public List<YoloLabel> Labels { get; set; } = new List<YoloLabel>();
}
}
namespace YOLO.Models
{
public class YoloModel
{
public int Dimensions { get; set; } //yolov7 包含nms 的模型不需要此参数

public string[] Outputs { get; set; }

public List<YoloLabel> Labels { get; set; } = new List<YoloLabel>();
}
}
20 changes: 3 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
# Usage
Yolo

```
Yolov8 yolov8 = new("path/to/.onnx");
yolov8.SetupLabels(<dict(str, color)>);
List<YoloPrediction> predictions = yolov8.Predict(<Image>, <dict(str, float)>, <confidence_level>, <iou_level>);
yolov8.SetupLabels(<dict(str, color)>)
yolov8.Predict(<Image>, <dict(str, color)>, <confidence_level>, <iou_level>)
```
RTDETR
```
RTDETR rtdetr = new("path/to/.onnx");
rtdetr.SetupLabels(<dict(str, color)>);
List<YoloPrediction> predictions = rtdetr.Predict(<Image>, <dict(str, float)>, <confidence_level>, <iou_level>);
```
OBB
```
OBB obb = new("path/to/.onnx");
obb.SetupLabels(<dict(str, color)>);
List<OBBPrediction> predictions = obb.Predict(<Image>, <dict(str, float)>, <confidence_level>, <iou_level>);
```
`<dict(str, float)>` is to control confidence level for each of the classes,
`<confidence_level>` is to control confidence level for all classes
Loading

0 comments on commit 85a68bf

Please sign in to comment.