I am using Onnxruntime in C# for yolov4.
Here is the pretrained yolo model:
https://github.com/onnx/models/tree/main/vision/object_detection_segmentation/yolov4/model
EmguCV is used to get an image, and then preprocess it to suit Yolo's input.
This is my preprocessing code:
static List<NamedOnnxValue> preprocess_CV(Mat im)
{
CvInvoke.Resize(im, im, new Size(416, 416));
var imData = im.ToImage<Bgr, Byte>().Data;
Tensor<float> input = new DenseTensor<float>(new[] {1, im.Height, im.Width, 3});
for (int x = 0; x < im.Width; x++)
for (int y = 0; y < im.Height; y++)
{
input[0, x, y, 0] = imData[x, y, 2] / (float)255.0;
input[0, x, y, 1] = imData[x, y, 1] / (float)255.0;
input[0, x, y, 2] = imData[x, y, 0] / (float)255.0;
}
List<NamedOnnxValue> inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("input_1:0", input) };
return inputs;
}
It works fine, but it is really slow, definitely because of nested fors.
So I decide to change it to the following code:
static List<NamedOnnxValue> preprocess_CV_v2(Mat im)
{
CvInvoke.Resize(im, im, new Size(416, 416));
im.ConvertTo(im, DepthType.Cv32F, 1 / 255.0);
CvInvoke.CvtColor(im, im, ColorConversion.Bgr2Rgb);
var imData = im.ToImage<Bgr, Byte>().Data;
var input = imData.ToTensor<float>();
List<NamedOnnxValue> inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("input_1:0", input) };
return inputs;
}
It does not use nested for and runs faster, but...
Output tensor shape of this code is (416,416,3), but yoloV4 need input tensor with shape (1,416,416,3).
How can I add a single dimension to onnx tensor or CV.Mat image, to fit my tensor to yoloV4 input?
It would be nice of you if you would help me with this problem.
Thanks in advance
Mary
I found one solution myself :D
It may help somebody else, with the same problem.
For me, this code is about 10 times faster than the original code (preprocess_CV function in the question).
static List<NamedOnnxValue> preprocess_CV_v2(Mat im)
{
CvInvoke.Resize(im, im, new Size(416, 416));
im.ConvertTo(im, DepthType.Cv32F, 1 / 255.0);
CvInvoke.CvtColor(im, im, ColorConversion.Bgr2Rgb);
var imData = im.ToImage<Bgr, float>().Data;
float[] imDataFlat = new float[imData.Length];
Buffer.BlockCopy(imData, 0, imDataFlat, 0, imData.Length * 4);
var inputTensor = new DenseTensor<float>(imDataFlat, new int[] { 1, im.Height, im.Width, 3 });
List<NamedOnnxValue> inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("input_1:0", inputTensor) };
return inputs;
}
Related
I'm looking to optimize a program that is basing a lot of its calculations on the rotation of a lot of 2D Points. I've search around to see if it's possible to do these calculations using SIMD in C#.
I found a c++ answer here that seems to do what I want, but I can't seem to translate this into C# using the System.Numerics.Vectors package.
Optimising 2D rotation
Can anyone point me in the right direction for how this can be done?
The below code shows the regular method without SIMD. Where Point is a struct with doubles X and Y.
public static Point[] RotatePoints(Point[] points, double cosAngle, double sinAngle)
{
var pointsLength = points.Length;
var results = new Point[pointsLength];
for (var i = 0; i < pointsLength; i++)
{
results[i].X = (points[i].X * cosAngle) - (points[i].Y * sinAngle);
results[i].Y = (points[i].X * sinAngle) + (points[i].Y * cosAngle);
}
return results;
}
Edit:
I've managed to get an implementation working using two Vector< float> but from benchmarking this, this seems to be a lot slower than the previous implementation.
private static void RotatePoints(float[] x, float[] y, float cosAngle, float sinAngle)
{
var chunkSize = Vector<float>.Count;
var resultX = new float[x.Length];
var resultY = new float[x.Length];
Vector<float> vectorChunk1;
Vector<float> vectorChunk2;
for (var i = 0; i < x.Length; i += chunkSize)
{
vectorChunk1 = new Vector<float>(x, i);
vectorChunk2 = new Vector<float>(y, i);
Vector.Subtract(Vector.Multiply(vectorChunk1, cosAngle), Vector.Multiply(vectorChunk2, sinAngle)).CopyTo(resultX, i);
Vector.Add(Vector.Multiply(vectorChunk1, sinAngle), Vector.Multiply(vectorChunk2, cosAngle)).CopyTo(resultY, i);
}
}
The code added in the edit is a good start, however the codegen for Vector.Multiply(Vector<float>, float) is extremely bad so this function should be avoided. It's an easy change to avoid it though, just broadcast outside the loop and multiply by a vector. I also added a more proper loop bound and "scalar epilog" in case the vector size does not neatly divide the size of the input arrays.
private static void RotatePoints(float[] x, float[] y, float cosAngle, float sinAngle)
{
var chunkSize = Vector<float>.Count;
var resultX = new float[x.Length];
var resultY = new float[x.Length];
Vector<float> vectorChunk1;
Vector<float> vectorChunk2;
Vector<float> vcosAngle = new Vector<float>(cosAngle);
Vector<float> vsinAngle = new Vector<float>(sinAngle);
int i;
for (i = 0; i + chunkSize - 1 < x.Length; i += chunkSize)
{
vectorChunk1 = new Vector<float>(x, i);
vectorChunk2 = new Vector<float>(y, i);
Vector.Subtract(Vector.Multiply(vectorChunk1, vcosAngle), Vector.Multiply(vectorChunk2, vsinAngle)).CopyTo(resultX, i);
Vector.Add(Vector.Multiply(vectorChunk1, vsinAngle), Vector.Multiply(vectorChunk2, vcosAngle)).CopyTo(resultY, i);
}
for (; i < x.Length; i++)
{
resultX[i] = x[i] * cosAngle - y[i] * sinAngle;
resultY[i] = x[i] * sinAngle + y[i] * cosAngle;
}
}
I am reading samples from a serial port continously and I want to show the last 400 samples in a graph.
So when the number of received samples becomes 400 I should shift the myPointFsList to left by 1 and add the last received sample
to the end of it. My below code works successfully while the first 400 samples.
List<PointF> myPointFs = new List<PointF>();
uint sampleNumber = 0; PointF Current_PointFs;
private void UpdateVar(object sender, EventArgs e){
...
Current_PointFs = new PointF((float)(sampleNumber), (float)newSample);
if (sampleNumber < 400)
{
myPointFs .Add(Current_PointFs);
++sampleNumber;
}
else
{
myPointFs = myPointFs .ShiftLeft(1); //ShiftLeft is an Extension Method
myPointFs.Add(Current_PointFs);
}
if (myPointFs.Count >= 2)
{
Configure_Graphs();// using Graphics.DrawLines(thin_pen, myPointFs.ToArray()) to draw chart
}
}
But after that the first 400 samples recieved, I need to substract 1 from myPointFs[i].X to shift X-axis to left by 1. Maybe a way is to run a for loop.
How can I implement it? Or is there any more elegant way? Or something that it exists out-of-the-box in C#?
Edit: (To make my question more clear)
myPointFs contains something like this:
myPointFs[0] = {X = 1, Y = 21}
myPointFs[1] = {X = 2, Y = 50}
myPointFs[2] = {X = 3, Y = 56}
now I will remove the first element by shifting left by 1 and add a new sample to the end.
myPointFs[0] = {X = 2, Y = 50}
myPointFs[1] = {X = 3, Y = 56}
myPointFs[2] = {X = 4, Y = 68}
But I need finally something like this:
myPointFs[0] = {X = 1, Y = 50}
myPointFs[1] = {X = 2, Y = 56}
myPointFs[2] = {X = 3, Y = 68}
So, you want to remove the first element and decrement the X value of each remaining point. You can do that in one go:
myPointFs = myPointFs.Skip(1).Select(p => new PointF(p.X-1, p.Y)).ToList();
That is job for Queue<T>. In your case X will be index and Y will be data inserted into Queue.
Here's some code to show how that works:
static void Main(string[] args)
{
var queue = new Queue<int>(10); //Capacity of Queue is 10
Console.WriteLine("=== Writing to Queue ===");
for (int i = 0; i < 23; ++i) //22 rounds for inserting data
{
DequeueIfFull(i, queue);
Console.WriteLine("Inserting number {0} into Queue", i);
queue.Enqueue(i); //Read and remove the first item in Queue
}
FlushQueue(queue); //Last time read all values from queue
Console.ReadKey();
}
private static void DequeueIfFull(int i, Queue<int> queue)
{
var tenthItemInserted = (i != 0) && (i % 10 == 0);
if (tenthItemInserted)
{
Console.WriteLine("Dequeuing from Queue");
for (int j = 0; j < 10; ++j)
{
Console.WriteLine(" Number dequeued on position {0} is {1}", j, queue.Dequeue());
}
}
}
private static void FlushQueue(Queue<int> queue)
{
Console.WriteLine();
Console.WriteLine("=== Reading final Queue state ===");
var index = 0;
foreach (var itemInQueue in queue)
{
Console.WriteLine("At position {0} is number {1} ", index, itemInQueue);
index++;
}
}
Documentation for Queue and link to nice articles about Data Structures.
I need to replicate this Excel graph in code
Given a list of [x, y] values, how can I obtain a new list of values to graph the power trendline?
I've found people referring to this http://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html formula. But don't know how to generate a new list of values from this.
Follow the formula from the link:
function getFittedPoints(data) {
var log = Math.log,
pow = Math.pow,
sums = [
0, // sum of the logarithms of x ( sum(log(x)) )
0, // sum of the logarithms of y ( sum(log(y)) )
0, // sum of the logarithms of the products of x and y ( sum(log(x) * log(y)) )
0 // sum of the powers of the logarithms of x ( sum((log(x))^2 )
],
fittedPoints = [], // return fitted points
a, // a coefficient
b, // b coefficient
dataLen = data.length,
i,
logX,
logY;
for (i = 0; i < dataLen; i++) {
sums[0] += logX = log(data[i][0]);
sums[1] += logY = log(data[i][1]);
sums[2] += logX * logY;
sums[3] += pow(logX, 2);
}
b = (i * sums[2] - sums[0] * sums[1]) / (i * sums[3] - pow(sums[0], 2));
a = pow(Math.E, (sums[1] - b * sums[0]) / i);
for (i = 0; i < dataLen; i++) {
fittedPoints.push([
data[i][0],
a * pow(data[i][0], b)
]);
}
return fittedPoints;
}
And then apply the function to the data.
example: http://jsfiddle.net/fa3m4Lvf/
Of course if your data are not clean then you can improve the function with handling null values,etc.
And for those like me who are looking for the C# version of morganfree's answer above, here it is translated:
public static IEnumerable<double> GetPowerTrendline(IList<double> knownY, IList<double> knownX, IList<double> newX)
{
var sums = new double[4];
var trendlinePoints = new List<double>();
var dataLen = knownX.Count;
for (var i = 0; i < dataLen; i++)
{
var logX = Math.Log(knownX[i]);
var logY = Math.Log(knownY[i]);
sums[0] += logX;
sums[1] += logY;
sums[2] += logX * logY;
sums[3] += Math.Pow(logX, 2);
}
var b = (dataLen * sums[2] - sums[0] * sums[1]) / (dataLen * sums[3] - Math.Pow(sums[0], 2));
var a = Math.Pow(Math.E, (sums[1] - b * sums[0]) / dataLen);
foreach (var x in newX)
{
var pointY = a * Math.Pow(x, b);
trendlinePoints.Add(pointY);
}
return trendlinePoints;
}
Note that it is modified so that it takes a list of desired x points instead of using the provided ones.
I followed the example calculation based on this: http://www.statisticshowto.com/how-to-find-a-linear-regression-equation/
Modified Adams example based on this and came upp with this solution for C#. This is assumes you have all the existing scatter plots. The result is a number of arraylists with the all the x and y values for the trendline that you can directly insert into highcharts.
public static List<ArrayList> GetPowerTrendline(List<KeyValuePair<int,double>> xyValues)
{
var trendlinePoints = new List<ArrayList>();
var dataLen = xyValues.Count;
var xSum = xyValues.Sum(h => h.Key);
var ySum = xyValues.Sum(h => h.Value);
var XYSum = xyValues.Sum(h => h.Key * h.Value);
var xp2Sum = xyValues.Sum(x => Math.Pow(x.Key, 2));
var a = (ySum * xp2Sum - xSum * XYSum) / (dataLen * xp2Sum - Math.Pow(xSum, 2));
var b = ((dataLen * XYSum) - (xSum * ySum)) / (dataLen * xp2Sum - Math.Pow(xSum,2));
foreach (var x in xyValues.OrderBy(h => h.Key))
{
var pointY = a + b * x.Key;
var rounded = Math.Round(pointY, 2);
trendlinePoints.Add(new ArrayList { x.Key, rounded });
}
return trendlinePoints;
}
And in my HighCharts method like this:
series: [
{
type: 'line',
name: 'Trendlinje',
data: data.RegressionLine,
color: '#444444',
marker: {
enabled: false
},
states: {
hover: {
lineWidth: 0
}
},
enableMouseTracking: false
},
how can I generate a "random constant colour" for a given string at runtime?
So a given string value will always have the same colour but different strings will have different colours.
Like how gmail assigns colours to the sender names.
Thanks
Responses to comments:
Thinking to generate the colour from a hashcode.
The colours won't be stored but generated from a hashcode.
I don't know any dedicated method for this, but here is a simple method generating Hexadecimal values with MD5 based on a given string:
using System.Security.Cryptography;
using System.Text;
static string GetColor(string raw)
{
using (MD5 md5Hash = MD5.Create())
{
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(raw));
return BitConverter.ToString(data).Replace("-", string.Empty).Substring(0, 6);
}
}
Examples:
example#example.com
-> 23463B
info#google.com
-> 3C9015
stack#exchange.com
-> 7CA5E8
Edit:
I didn't tested it enough, so you may want to tweak it a little bit to get more different and unique values.
Edit2:
If you want transparency, check out this question/answer. By setting the Substring to Substring(0,8) , you should return a string with the alpha channel.
Similar to what the other answers are suggesting (hash the string in some form then use that hash to pick the color), but instead of using the hash to directly calculate the color use it as the index to an array of "Acceptable" colors.
class ColorPicker
{
public ColorPicker(int colorCount)
{
//The ".Skip(2)" makes it skip pure white and pure black.
// If you want those two, take out the +2 and the skip.
_colors = ColorGenerator.Generate(colorCount + 2).Skip(2).ToArray();
}
private readonly Color[] _colors;
public Color StringToColor(string message)
{
int someHash = CalculateHashOfStringSomehow(message);
return _colors[someHash % _colors.Length];
}
private int CalculateHashOfStringSomehow(string message)
{
//TODO: I would not use "message.GetHashCode()" as you are not
// guaranteed the same value between runs of the program.
// Make up your own algorithom or use a existing one that has a fixed
// output for a given input, like MD5.
}
}
This prevents issues like getting a white color when you plan on showing the text with a white background and other similar problems.
To populate your Color[] see this answer for the ColorGenerator class or just make your own pre-defined list of colors that look good on whatever background they will be used on.
Appendix:
In case the link goes down, here is a copy of the ColorGenerator class
public static class ColorGenerator
{
// RYB color space
private static class RYB
{
private static readonly double[] White = { 1, 1, 1 };
private static readonly double[] Red = { 1, 0, 0 };
private static readonly double[] Yellow = { 1, 1, 0 };
private static readonly double[] Blue = { 0.163, 0.373, 0.6 };
private static readonly double[] Violet = { 0.5, 0, 0.5 };
private static readonly double[] Green = { 0, 0.66, 0.2 };
private static readonly double[] Orange = { 1, 0.5, 0 };
private static readonly double[] Black = { 0.2, 0.094, 0.0 };
public static double[] ToRgb(double r, double y, double b)
{
var rgb = new double[3];
for (int i = 0; i < 3; i++)
{
rgb[i] = White[i] * (1.0 - r) * (1.0 - b) * (1.0 - y) +
Red[i] * r * (1.0 - b) * (1.0 - y) +
Blue[i] * (1.0 - r) * b * (1.0 - y) +
Violet[i] * r * b * (1.0 - y) +
Yellow[i] * (1.0 - r) * (1.0 - b) * y +
Orange[i] * r * (1.0 - b) * y +
Green[i] * (1.0 - r) * b * y +
Black[i] * r * b * y;
}
return rgb;
}
}
private class Points : IEnumerable<double[]>
{
private readonly int pointsCount;
private double[] picked;
private int pickedCount;
private readonly List<double[]> points = new List<double[]>();
public Points(int count)
{
pointsCount = count;
}
private void Generate()
{
points.Clear();
var numBase = (int)Math.Ceiling(Math.Pow(pointsCount, 1.0 / 3.0));
var ceil = (int)Math.Pow(numBase, 3.0);
for (int i = 0; i < ceil; i++)
{
points.Add(new[]
{
Math.Floor(i/(double)(numBase*numBase))/ (numBase - 1.0),
Math.Floor((i/(double)numBase) % numBase)/ (numBase - 1.0),
Math.Floor((double)(i % numBase))/ (numBase - 1.0),
});
}
}
private double Distance(double[] p1)
{
double distance = 0;
for (int i = 0; i < 3; i++)
{
distance += Math.Pow(p1[i] - picked[i], 2.0);
}
return distance;
}
private double[] Pick()
{
if (picked == null)
{
picked = points[0];
points.RemoveAt(0);
pickedCount = 1;
return picked;
}
var d1 = Distance(points[0]);
int i1 = 0, i2 = 0;
foreach (var point in points)
{
var d2 = Distance(point);
if (d1 < d2)
{
i1 = i2;
d1 = d2;
}
i2 += 1;
}
var pick = points[i1];
points.RemoveAt(i1);
for (int i = 0; i < 3; i++)
{
picked[i] = (pickedCount * picked[i] + pick[i]) / (pickedCount + 1.0);
}
pickedCount += 1;
return pick;
}
public IEnumerator<double[]> GetEnumerator()
{
Generate();
for (int i = 0; i < pointsCount; i++)
{
yield return Pick();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static IEnumerable<Color> Generate(int numOfColors)
{
var points = new Points(numOfColors);
foreach (var point in points)
{
var rgb = RYB.ToRgb(point[0], point[1], point[2]);
yield return Color.FromArgb(
(int)Math.Floor(255 * rgb[0]),
(int)Math.Floor(255 * rgb[1]),
(int)Math.Floor(255 * rgb[2]));
}
}
}
3 integer variables, r,g and b.
Loop through each character in the string in steps of 3 and add the character code.
r += n + 0
g += n + 1
b += n + 2
after the loop take r,g, and b modulo 255 and create a color using Color.FromARGB.
No guarantees the color will be pretty though, and some strings may happen to have colors very close to each other.
I see some pretty good answeers but though it whould contribute with a little fun solutuion to generate colors from string, the Hash version looks like the best way to go but if this gives any one some inspiration to bould off, have at it
ConsoleKeyInfo ch = new ConsoleKeyInfo();
while (ch.KeyChar != 'e')
{
Console.WriteLine("type string to seed color");
string s = Console.ReadLine(); // gets text from input, in this case the command line
double d=0;
foreach(char cha in s.ToCharArray())
{
d=+ (int)cha; // get the value and adds it
}
d= (255/(Math.Pow(0.2,-0.002 *d))); // Generates a seed like value from i where 255 is the maximum. basicly 255/0.2^(-0.002*d)
int i = Convert.ToInt32(d); //then convets and get rid of the decimels
Color c = Color.FromArgb(i, i, i);// add a bit more calculation for varieng colers.
Console.WriteLine(c.Name);
Console.WriteLine("To Exit press e");
ch = Console.ReadKey()
}
Edit1: It definantly needs some tweeking, since the longer the string the ligther the color, but i think something can come from it with a little work :)
I'm writing a small application in C# using MSChart control to do Scatter Plots of sets of X and Y data points. Some of these can be rather large (hundreds of data points).
Wanted to ask if there's a 'standard' algorith for plotting a best-fit line across the points. I'm thinking to divide the X data points to a predefined number of sets, say 10 or 20, and for each set take the average of the corresponding Y values and the middle X value, and so on to create the line. Is this a correct approach?
I've searched existing threads but they all seem to be about achieving the same using existing applications like Matlab.
Thanks,
using a Linear least squares algorithm
public class XYPoint
{
public int X;
public double Y;
}
class Program
{
public static List<XYPoint> GenerateLinearBestFit(List<XYPoint> points, out double a, out double b)
{
int numPoints = points.Count;
double meanX = points.Average(point => point.X);
double meanY = points.Average(point => point.Y);
double sumXSquared = points.Sum(point => point.X * point.X);
double sumXY = points.Sum(point => point.X * point.Y);
a = (sumXY / numPoints - meanX * meanY) / (sumXSquared / numPoints - meanX * meanX);
b = (a * meanX - meanY);
double a1 = a;
double b1 = b;
return points.Select(point => new XYPoint() { X = point.X, Y = a1 * point.X - b1 }).ToList();
}
static void Main(string[] args)
{
List<XYPoint> points = new List<XYPoint>()
{
new XYPoint() {X = 1, Y = 12},
new XYPoint() {X = 2, Y = 16},
new XYPoint() {X = 3, Y = 34},
new XYPoint() {X = 4, Y = 45},
new XYPoint() {X = 5, Y = 47}
};
double a, b;
List<XYPoint> bestFit = GenerateLinearBestFit(points, out a, out b);
Console.WriteLine("y = {0:#.####}x {1:+#.####;-#.####}", a, -b);
for(int index = 0; index < points.Count; index++)
{
Console.WriteLine("X = {0}, Y = {1}, Fit = {2:#.###}", points[index].X, points[index].Y, bestFit[index].Y);
}
}
}
Yes. You will want to use Linear Regression, specifically Simple Linear Regression.
The algorithm is essentially:
assume there exists a line of best fit, y = ax + b
for each of your points, you want to minimise their distance from this line
calculate the distance for each point from the line, and sum the distances (normally we use the square of the distance to more heavily penalise points further from the line)
find the values of a and b that minimise the resulting equation using basic calculus (there should be only one minimum)
The wikipedia page will give you everything you need.