332 lines
11 KiB
C#
332 lines
11 KiB
C#
using OpenCvSharp;
|
|
using ZXing;
|
|
using ZXing.QrCode;
|
|
using OpenCvSharp.Extensions;
|
|
using ZXing.Windows.Compatibility;
|
|
using ZXing.Common;
|
|
using System.Runtime.InteropServices;
|
|
using System.Drawing;
|
|
using System.Net;
|
|
using System.Runtime.InteropServices.Marshalling;
|
|
using Emgu.CV.Face;
|
|
using System.Transactions;
|
|
|
|
// using Emgu.CV.CvEnum;
|
|
|
|
|
|
namespace BarcodeReaderExample
|
|
{
|
|
class Program
|
|
{
|
|
static bool draw;
|
|
static void Main(string[] args)
|
|
{
|
|
VideoCapture camera = new VideoCapture("/dev/video0", VideoCaptureAPIs.V4L2);
|
|
|
|
if (!camera.IsOpened())
|
|
throw new Exception("Nie można otworzyć kamery /dev/video0");
|
|
|
|
camera.Set(VideoCaptureProperties.FrameWidth, 1280);
|
|
camera.Set(VideoCaptureProperties.FrameHeight, 720);
|
|
int fps = 60;
|
|
int avalibeImages = 20;
|
|
camera.Set(VideoCaptureProperties.Fps, fps);
|
|
if (Directory.Exists("cache"))
|
|
{
|
|
Directory.Delete("cache", true);
|
|
}
|
|
|
|
Directory.CreateDirectory("cache");
|
|
Mat hey = new Mat("photo.png");
|
|
Mat[] Cached = new Mat[avalibeImages];
|
|
draw = true;
|
|
|
|
int imgX = 0;
|
|
int imgY = 0;
|
|
|
|
using var rgb = new Mat();
|
|
|
|
// OpenCV stores camera frames as BGR.
|
|
// ZXing's RGBLuminanceSource expects RGB.
|
|
// Cv2.CvtColor(frame, rgb, ColorConversionCodes.BGR2RGB);
|
|
|
|
|
|
|
|
Cv2.NamedWindow("Camera preview", WindowFlags.AutoSize);
|
|
// Mat src = Cv2.ImRead("test.png");
|
|
int whenWasLastTimeQrDetected = 0;
|
|
Mat Lastimage = new Mat();
|
|
IEnumerable<IEnumerable<OpenCvSharp.Point>> contours = null;
|
|
// PointF[] location;
|
|
Mat previue = new Mat();
|
|
string[] files = new string[avalibeImages];
|
|
int files_index = 0;
|
|
while (true)
|
|
{
|
|
|
|
|
|
camera.Read(frame);
|
|
|
|
Result result = ReadQrCode(frame);
|
|
// Console.WriteLine(Lastimage.Empty());
|
|
if (!(Lastimage.Empty()))
|
|
{
|
|
Cv2.Resize(Lastimage, previue, new OpenCvSharp.Size(500, 500));
|
|
|
|
Mat roi2 = frame[new Rect(0, 0, previue.Width, previue.Height)];
|
|
previue.CopyTo(roi2);
|
|
}
|
|
|
|
if (result != null)
|
|
{
|
|
whenWasLastTimeQrDetected = 5;
|
|
List<ResultPoint> points = result.ResultPoints.ToList();
|
|
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[] pos3 = new float[2] { points[1].X, points[1].Y }; ///lewy górny róg
|
|
int width = (int)(pos2[0] - pos3[0]);
|
|
int heigh = (int)(pos1[1] - pos3[1]);
|
|
|
|
PointF[] location;
|
|
try
|
|
{
|
|
|
|
location = Calculate(pos1, pos2, pos3, new float[2] { points[3].X, points[3].Y });
|
|
}
|
|
catch
|
|
{
|
|
continue;
|
|
}
|
|
var points1 = new List<OpenCvSharp.Point>
|
|
{
|
|
GetPoint(location[0]),
|
|
GetPoint(location[1]),
|
|
GetPoint(location[3]),
|
|
GetPoint(location[2])
|
|
};
|
|
int qrWidth = GetPoint(location[1]).X - GetPoint(location[0]).X;
|
|
int qrHeigh = GetPoint(location[2]).Y - GetPoint(location[0]).Y;
|
|
|
|
|
|
imgX = GetPoint(location[0]).X;
|
|
imgY = GetPoint(location[0]).Y;
|
|
contours = new[] { points1 };
|
|
|
|
if (draw)
|
|
Cv2.FillPoly(frame, contours, Scalar.White); // fill with white
|
|
|
|
//Write Text
|
|
// Cv2.PutText(frame, result.Text, new OpenCvSharp.Point((int)(pos2[0]-pos3[0])/2+(int)pos3[0]-160, (int)(pos2[1]-pos3[1])/2+(int)pos3[1]+60), HersheyFonts.HersheySimplex, 0.8, Scalar.Black, 2);
|
|
|
|
if (!files.Contains(result.Text))
|
|
{
|
|
files[files_index] = result.Text;
|
|
Console.WriteLine("downloading: " + result.Text);
|
|
|
|
using (var client = new WebClient())
|
|
{
|
|
client.DownloadFile(result.Text, "cache/" + files_index + ".png");
|
|
// Thread.Sleep(2000);
|
|
|
|
}
|
|
Cached[files_index] = new Mat("cache/" + files_index + ".png");
|
|
files_index++;
|
|
}
|
|
else
|
|
{
|
|
|
|
int toload = files.IndexOf(result.Text);
|
|
Mat toDraw= new Mat();
|
|
|
|
|
|
InputArray inputArray = toDraw;
|
|
// Console.WriteLine($"{qrWidth} , {qrHeigh}");
|
|
|
|
try
|
|
{
|
|
|
|
Cv2.Resize(Cached[toload],toDraw,new OpenCvSharp.Size(qrWidth,qrHeigh));
|
|
}
|
|
catch
|
|
{ continue; }
|
|
Lastimage = toDraw;
|
|
|
|
// toDraw.Resize(1,3);
|
|
try
|
|
{
|
|
|
|
// Mat roi2 = frame[new Rect(GetPoint(location[0]).X, GetPoint(location[0]).Y, toDraw.Width, toDraw.Height)];
|
|
// toDraw.CopyTo(roi2);
|
|
DrawImage(toDraw, GetPoint(location[0]).X, GetPoint(location[0]).Y);
|
|
|
|
}
|
|
catch { }
|
|
|
|
}
|
|
|
|
|
|
}
|
|
else if (whenWasLastTimeQrDetected > 0)
|
|
{
|
|
Cv2.FillPoly(frame, contours, Scalar.White); // fill with white
|
|
|
|
try
|
|
{
|
|
// Mat roi2 = frame[new Rect(imgX, imgY, Lastimage.Width, Lastimage.Height)];
|
|
// Lastimage.CopyTo(roi2);
|
|
|
|
DrawImage(Lastimage,imgX,imgY);
|
|
}
|
|
catch { }
|
|
whenWasLastTimeQrDetected--;
|
|
|
|
}
|
|
|
|
|
|
Cv2.ImShow("Camera preview", frame);
|
|
Thread.Sleep(1000 / fps);
|
|
|
|
int key = Cv2.WaitKey(1);
|
|
if (key == 27 || key == 'q')
|
|
break;
|
|
}
|
|
|
|
Cv2.DestroyAllWindows();
|
|
|
|
}
|
|
|
|
static void DrawImage(Mat image, int posX, int posY)
|
|
{
|
|
if(draw)
|
|
{
|
|
|
|
Mat roi2 = frame[new Rect(posX, posY, image.Width, image.Height)];
|
|
image.CopyTo(roi2);
|
|
}
|
|
}
|
|
static OpenCvSharp.Point GetPoint(PointF pointf)
|
|
{
|
|
return new OpenCvSharp.Point(pointf.X, pointf.Y);
|
|
}
|
|
static PointF[] 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);
|
|
PointF[] Location = new PointF[] { topLeft, topRight, bottomLeft, bottomRight };
|
|
return Location;
|
|
// 4. Now draw the 4 lines
|
|
// Example with System.Drawing or Unity or whatever you use:
|
|
|
|
}
|
|
static void DrawLine(PointF p1, PointF p2)
|
|
{
|
|
if(draw)
|
|
{
|
|
|
|
Cv2.Line(frame, (int)p1.X, (int)p1.Y, (int)p2.X, (int)p2.Y, Scalar.Red, 2);
|
|
}
|
|
|
|
}
|
|
static void DrawLine(PointF[] Location)
|
|
{
|
|
DrawLine(Location[0], Location[1]);
|
|
|
|
|
|
DrawLine(Location[1], Location[2]);
|
|
DrawLine(Location[2], Location[3]);
|
|
DrawLine(Location[3], Location[0]);
|
|
|
|
}
|
|
static void DrawLine(float x1, float y1, float x2, float y2)
|
|
{
|
|
Cv2.Line(frame, (int)x1, (int)y1, (int)x2, (int)y2, Scalar.Red, 2);
|
|
}
|
|
static Mat frame = new Mat();
|
|
|
|
static Result ReadQrCode(Mat frame)
|
|
{
|
|
|
|
QRCodeReader reader = new QRCodeReader();
|
|
Result result = reader.decode(MatToBinaryBitmap(frame));
|
|
return result;
|
|
}
|
|
static BinaryBitmap MatToBinaryBitmap(Mat frame)
|
|
{
|
|
if (frame.Empty())
|
|
throw new ArgumentException("The Mat is empty.", nameof(frame));
|
|
|
|
using var rgb = new Mat();
|
|
|
|
// OpenCV uses BGR; ZXing RGBLuminanceSource expects RGB.
|
|
Cv2.CvtColor(
|
|
frame,
|
|
rgb,
|
|
ColorConversionCodes.BGR2RGB
|
|
);
|
|
|
|
// Clone ensures contiguous pixel memory.
|
|
using var contiguous = rgb.Clone();
|
|
|
|
int width = contiguous.Width;
|
|
int height = contiguous.Height;
|
|
|
|
int byteCount = checked(
|
|
(int)(contiguous.Total() * contiguous.ElemSize())
|
|
);
|
|
|
|
byte[] pixels = new byte[byteCount];
|
|
|
|
Marshal.Copy(
|
|
contiguous.Data,
|
|
pixels,
|
|
0,
|
|
pixels.Length
|
|
);
|
|
|
|
var luminanceSource = new RGBLuminanceSource(
|
|
pixels,
|
|
width,
|
|
height,
|
|
RGBLuminanceSource.BitmapFormat.RGB24
|
|
);
|
|
|
|
return new BinaryBitmap(
|
|
new HybridBinarizer(luminanceSource)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|