This commit is contained in:
Kq
2026-08-12 02:10:09 +02:00
parent 5c4a872490
commit 21fa6726f4
9 changed files with 51 additions and 177 deletions
+47 -173
View File
@@ -4,8 +4,8 @@ using ZXing.QrCode;
using OpenCvSharp.Extensions; using OpenCvSharp.Extensions;
using ZXing.Windows.Compatibility; using ZXing.Windows.Compatibility;
using ZXing.Common; using ZXing.Common;
using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Drawing;
namespace BarcodeReaderExample namespace BarcodeReaderExample
@@ -24,7 +24,6 @@ namespace BarcodeReaderExample
camera.Set(VideoCaptureProperties.Fps, 5); camera.Set(VideoCaptureProperties.Fps, 5);
// Mat frame = new Mat();
Mat hey = new Mat("photo.png"); Mat hey = new Mat("photo.png");
@@ -58,19 +57,13 @@ namespace BarcodeReaderExample
float[] pos1 = new float[2] {points[0].X, points[0].Y}; /// lewy dolny róg float[] pos1 = new float[2] {points[0].X, points[0].Y}; /// lewy dolny róg
float[] pos2 = new float[2] {points[2].X, points[2].Y}; ///prawy górny róg float[] pos2 = new float[2] {points[2].X, points[2].Y}; ///prawy górny róg
float[] pos3 = new float[2] { points[1].X, points[1].Y }; ///lewy górny róg float[] pos3 = new float[2] { points[1].X, points[1].Y }; ///lewy górny róg
float[] pos4 = new float[2] { points[3].X, points[3].Y }; ///prawy dolny róg
// Cv2.Circle(frame, (int)pos1[0], (int)pos1[1], 5, Scalar.Red, 2); // Cv2.Circle(frame, (int)pos1[0], (int)pos1[1], 5, Scalar.Red, 2);
// Cv2.Circle(frame, (int)pos2[0], (int)pos2[1], 5, Scalar.Green, 2); // Cv2.Circle(frame, (int)pos2[0], (int)pos2[1], 5, Scalar.Green, 2);
// Cv2.Circle(frame, (int)pos3[0], (int)pos3[1], 5, Scalar.Blue, 2); // Cv2.Circle(frame, (int)pos3[0], (int)pos3[1], 5, Scalar.Blue, 2);
Cv2.PutText(frame, result.Text, new OpenCvSharp.Point((int)pos1[0], (int)pos1[1] - 10), HersheyFonts.HersheySimplex, 1, Scalar.Red, 2);
Executeit(pos1, pos2, pos3, pos4); Calculate(pos1, pos2, pos3, new float[2] { points[3].X, points[3].Y });
// DrawLine(new PointF(LeftBottomX, LeftBottomY), new PointF(LeftTopX, LeftTopY));
// DrawLine(new PointF(RightTopX, RightTopY), new PointF(LeftTopX, LeftTopY));
// DrawLine(new PointF(LeftBottomX, LeftBottomY), new PointF(RightBottomX, RightBottomY));
// DrawLine(new PointF(RightTopX, RightTopY), new PointF(RightBottomX, RightBottomY));
// Cv2.Circle(frame, (int)(RightBottomX), (int)(RightBottomY), 5, Scalar.Green, 2); // Cv2.Circle(frame, (int)(RightBottomX), (int)(RightBottomY), 5, Scalar.Green, 2);
@@ -96,7 +89,50 @@ namespace BarcodeReaderExample
Cv2.DestroyAllWindows(); Cv2.DestroyAllWindows();
} }
static Mat frame = new Mat(); static void Calculate(float[] pos1, float[] pos2, float[] pos3, float[] pos4)
{
// Your 4 detected points (change the names if needed)
PointF p1 = new PointF(pos1[0], pos1[1]);
PointF p2 = new PointF(pos2[0], pos2[1]);
PointF p3 = new PointF(pos3[0], pos3[1]);
PointF p4 = new PointF(pos4[0], pos4[1]);
// 1. Find the center of the QR
float centerX = (p1.X + p2.X + p3.X + p4.X) / 4f;
float centerY = (p1.Y + p2.Y + p3.Y + p4.Y) / 4f;
PointF center = new PointF(centerX, centerY);
// 2. How much bigger you want the box (1.0 = exact size, 1.15 = 15% bigger)
float scale = 1.35f; // ← change this value
// 3. Move every corner away from the center
PointF Expand(PointF p)
{
float dx = p.X - center.X;
float dy = p.Y - center.Y;
return new PointF(center.X + dx * scale, center.Y + dy * scale);
}
float scaleLB = 1.75f; // ← change this value
PointF ExpandLB(PointF p)
{
float dx = p.X - center.X;
float dy = p.Y - center.Y;
return new PointF(center.X + dx * scaleLB, center.Y + dy * scaleLB);
}
PointF topLeft = Expand(p3); // change order if needed
PointF topRight = Expand(p2);
PointF bottomRight = ExpandLB(p4);
PointF bottomLeft = Expand(p1);
// 4. Now draw the 4 lines
// Example with System.Drawing or Unity or whatever you use:
DrawLine(topLeft, topRight);
DrawLine(topRight, bottomRight);
DrawLine(bottomRight, bottomLeft);
DrawLine(bottomLeft, topLeft);
}
static void DrawLine(PointF p1, PointF p2) static void DrawLine(PointF p1, PointF p2)
{ {
Cv2.Line(frame, (int)p1.X, (int)p1.Y, (int)p2.X, (int)p2.Y, Scalar.Red, 2); Cv2.Line(frame, (int)p1.X, (int)p1.Y, (int)p2.X, (int)p2.Y, Scalar.Red, 2);
@@ -106,27 +142,7 @@ namespace BarcodeReaderExample
{ {
Cv2.Line(frame, (int)x1, (int)y1, (int)x2, (int)y2, Scalar.Red, 2); Cv2.Line(frame, (int)x1, (int)y1, (int)x2, (int)y2, Scalar.Red, 2);
} }
static Mat frame = new Mat();
static void Executeit(float[] pos1, float[] pos2, float[] pos3, float[] pos4)
{
// Your detected points
QrOverlay.Pt[] raw = {
new QrOverlay.Pt(pos1[0], pos1[1]),
new QrOverlay.Pt(pos2[0], pos2[1]),
new QrOverlay.Pt(pos3[0], pos3[1]),
new QrOverlay.Pt(pos4[0], pos4[1])
};
// Get the expanded corners (margin = 0.10 → 10% bigger, try 0.08–0.18)
QrOverlay.Pt[] box = QrOverlay.GetExpandedCorners(raw, 0.12f);
// Draw
DrawLine(box[0].X, box[0].Y, box[1].X, box[1].Y);
DrawLine(box[1].X, box[1].Y, box[2].X, box[2].Y);
DrawLine(box[2].X, box[2].Y, box[3].X, box[3].Y);
DrawLine(box[3].X, box[3].Y, box[0].X, box[0].Y);
}
static Result GetResult(Mat frame) static Result GetResult(Mat frame)
{ {
@@ -135,25 +151,6 @@ namespace BarcodeReaderExample
Result result = reader.decode(MatToBinaryBitmap(frame)); Result result = reader.decode(MatToBinaryBitmap(frame));
return result; return result;
} }
// Sorts any 4 points into: Top-Left, Top-Right, Bottom-Right, Bottom-Left
static PointF[] SortQrCorners(PointF[] points)
{
// 1. Find center
float cx = (points[0].X + points[1].X + points[2].X + points[3].X) / 4f;
float cy = (points[0].Y + points[1].Y + points[2].Y + points[3].Y) / 4f;
PointF tl = new PointF(), tr = new PointF(), br = new PointF(), bl = new PointF();
foreach (var p in points)
{
if (p.X < cx && p.Y < cy) tl = p; // top-left
else if (p.X > cx && p.Y < cy) tr = p; // top-right
else if (p.X > cx && p.Y > cy) br = p; // bottom-right
else bl = p; // bottom-left
}
return new PointF[] { tl, tr, br, bl };
}
static BinaryBitmap MatToBinaryBitmap(Mat frame) static BinaryBitmap MatToBinaryBitmap(Mat frame)
{ {
if (frame.Empty()) if (frame.Empty())
@@ -199,129 +196,6 @@ namespace BarcodeReaderExample
); );
} }
} }
public static class QrOverlay
{
public struct Pt
{
public float X, Y;
public Pt(float x, float y) { X = x; Y = y; }
}
// Main function you call every frame
public static Pt[] GetExpandedCorners(Pt[] rawPoints, float margin = 0.12f)
{
// 1. Sort
var sorted = Sort(rawPoints);
Pt tl = sorted[0], tr = sorted[1], br = sorted[2], bl = sorted[3];
// 2. Fix weak bottom-right
br = new Pt(tr.X + bl.X - tl.X, tr.Y + bl.Y - tl.Y);
// 3. Canonical square (0..1)
Pt[] canonical = {
new Pt(0, 0),
new Pt(1, 0),
new Pt(1, 1),
new Pt(0, 1)
};
// 4. Expanded canonical square
Pt[] expanded = {
new Pt(-margin, -margin),
new Pt(1 + margin, -margin),
new Pt(1 + margin, 1 + margin),
new Pt(-margin, 1 + margin)
};
// 5. Homography: canonical → image
float[] H = FindHomography(canonical, new[] { tl, tr, br, bl });
// 6. Transform the expanded points back to image
Pt[] result = new Pt[4];
for (int i = 0; i < 4; i++)
result[i] = Transform(H, expanded[i]);
return result;
}
// ---------- helpers ----------
static Pt[] Sort(Pt[] pts)
{
float cx = (pts[0].X + pts[1].X + pts[2].X + pts[3].X) * 0.25f;
float cy = (pts[0].Y + pts[1].Y + pts[2].Y + pts[3].Y) * 0.25f;
Pt tl = default, tr = default, br = default, bl = default;
foreach (var p in pts)
{
if (p.X < cx && p.Y < cy) tl = p;
else if (p.X >= cx && p.Y < cy) tr = p;
else if (p.X >= cx && p.Y >= cy) br = p;
else bl = p;
}
return new[] { tl, tr, br, bl };
}
static Pt Transform(float[] H, Pt p)
{
float x = H[0] * p.X + H[1] * p.Y + H[2];
float y = H[3] * p.X + H[4] * p.Y + H[5];
float w = H[6] * p.X + H[7] * p.Y + H[8];
return new Pt(x / w, y / w);
}
// Simple but robust 4-point homography (DLT)
static float[] FindHomography(Pt[] src, Pt[] dst)
{
// Build the 8x9 matrix and solve with Gaussian elimination
float[,] A = new float[8, 9];
for (int i = 0; i < 4; i++)
{
float x = src[i].X, y = src[i].Y;
float u = dst[i].X, v = dst[i].Y;
A[i * 2, 0] = x; A[i * 2, 1] = y; A[i * 2, 2] = 1;
A[i * 2, 6] = -u * x; A[i * 2, 7] = -u * y; A[i * 2, 8] = -u;
A[i * 2 + 1, 3] = x; A[i * 2 + 1, 4] = y; A[i * 2 + 1, 5] = 1;
A[i * 2 + 1, 6] = -v * x; A[i * 2 + 1, 7] = -v * y; A[i * 2 + 1, 8] = -v;
}
// Gaussian elimination to find null-space (last column)
// (simplified solver – works well for QR)
for (int i = 0; i < 8; i++)
{
// Pivot
int pivot = i;
for (int j = i + 1; j < 8; j++)
if (Math.Abs(A[j, i]) > Math.Abs(A[pivot, i])) pivot = j;
for (int k = 0; k < 9; k++)
{
float tmp = A[i, k];
A[i, k] = A[pivot, k];
A[pivot, k] = tmp;
}
float div = A[i, i];
if (Math.Abs(div) < 1e-8f) continue;
for (int k = i; k < 9; k++) A[i, k] /= div;
for (int j = 0; j < 8; j++)
{
if (j == i) continue;
float f = A[j, i];
for (int k = i; k < 9; k++)
A[j, k] -= f * A[i, k];
}
}
float[] H = new float[9];
for (int i = 0; i < 8; i++) H[i] = -A[i, 8];
H[8] = 1f;
return H;
}
}
} }
Binary file not shown.
Binary file not shown.
@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("CameraPreview")] [assembly: System.Reflection.AssemblyCompanyAttribute("CameraPreview")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5c4a8724900fa1d2eb91d0cfbb4d2d21dca098ef")]
[assembly: System.Reflection.AssemblyProductAttribute("CameraPreview")] [assembly: System.Reflection.AssemblyProductAttribute("CameraPreview")]
[assembly: System.Reflection.AssemblyTitleAttribute("CameraPreview")] [assembly: System.Reflection.AssemblyTitleAttribute("CameraPreview")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
@@ -1 +1 @@
5a5149973964cffcb89d8df3cd5f6ea5f2e90db02df04f8185c0798d2a8e4b9c c2e8dfba618610c2f16f0f2947d9d269a0e001774f8e688ff18a9515da8c898c
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.