Reputation: 3
I have already visited as many answers on here about the System.AccessViolationException: 'Attempted to read or write protected memory.
error and they all seem to be about something else that is not todo with pictures.
I am learning image processing but I am somewhat still learning the debugging of software. I am trying to search for an image inside another image using the featured based image detection with BRISK and the Brute force method. However for some reason every time I run and click the button2 I get the above error, I have no idea how to debug this. The exception is being thrown on the line matcher.KnnMatch(sceneDescriptor, matches, k);
the value of matches is null when I hover over it.
I have used NuGet in visual studio 2019 to install Emgu.CV vs 4.5.1, Emgu.cv.bitmap, emgu.cv.runtime.windows 4.5.1. I have even tried changing my compile mode from x86 to x64. I have no idea what I am doing wrong.
File - myImgprocessing.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu;
using Emgu.CV;
using Emgu.CV.Structure;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using Emgu.CV.Util;
using Emgu.CV.Features2D; // for brisk/ feature detectors
namespace mine
{
class MyImageProcessing
{
// store in memory any images we want to use
Dictionary<string, Image<Bgr, byte>> imgDict; // imgDict.Add("shark",img);
public Bitmap findImgFB(Image<Bgr, byte> sourceImg, Image<Bgr, byte> targetImg)
{
if ((sourceImg != null) && (targetImg != null))
{
var localImgSourceC = sourceImg.Clone();
var localImgSource = localImgSourceC.ToBitmap().ToImage<Gray, byte>();
var localImgTargetC = targetImg.Clone();
var localImgTarget = localImgTargetC.ToBitmap().ToImage<Gray, byte>();
//return localImgTarget.AsBitmap();
var myfoundPoints = processFBBrutforce(localImgTarget, localImgSource);
if(myfoundPoints != null)
{
// draw it now
CvInvoke.Polylines(sourceImg, myfoundPoints, true, new MCvScalar(0,0,255),5);
}
else
{
MessageBox.Show("cant find points to draw");
}
return sourceImg.AsBitmap(); // efficient way to convert gray image byte to grayscale
}
return new Bitmap(5, 5);
}
private static VectorOfPoint processFBBrutforce(Image<Gray, byte> target, Image<Gray, byte> sceneimg)
{
try
{
//
// initialization start
VectorOfPoint pointsToReturn = null;
Mat homography = null;
VectorOfKeyPoint targetKeyPoints = new VectorOfKeyPoint(); // key points stored here
VectorOfKeyPoint sceneKeyPoints = new VectorOfKeyPoint();
VectorOfVectorOfDMatch matches = null; // storing matches
Mat sceneDescriptor = new Mat();
Mat targetDescriptor = new Mat();
int k = 2; // NUMBER OF NEAREST MATCHES TO RETURN for uniquenes
Double uniqueThreshold = 0.80; // this is for finding neighbour matches so that it does not find duplicates and only uniques, tweak this number for results
Mat mask;
//descriptor and feature detection to use, tweak this for different results
Brisk featureDetector = new Brisk();
featureDetector.DetectAndCompute(target, null, targetKeyPoints, targetDescriptor,false); // give it img, place to store key points/descriptor, and false cus we need it to get key points
featureDetector.DetectAndCompute(sceneimg, null, sceneKeyPoints, sceneDescriptor, false);
// initialization end
//
// matching part - this is a brute-force matcher
BFMatcher matcher = new BFMatcher(DistanceType.Hamming);// we have to use 'hamming' distance calculator method because we are using BRISK feature detector above, can tweak respectively
matcher.Add(targetDescriptor);// give it model
matcher.KnnMatch(sceneDescriptor, matches, k);// match it with model and store in matches variable
// create a mask and set those values to 255
mask = new Mat(matches.Size,1,Emgu.CV.CvEnum.DepthType.Cv8U, 1);// 1 column, 8bit unsigned depth type, 1 channel image
mask.SetTo(new MCvScalar(255));
// goes through the masks and looks for match and sets to 255 or 0 for no match
Features2DToolbox.VoteForUniqueness(matches, uniqueThreshold, mask);
// give only the allowed scaled and rotated matches so it doesnt go past a certain point, this rejects any matches without the below requirements
int count = Features2DToolbox.VoteForSizeAndOrientation(targetKeyPoints, sceneKeyPoints, matches, mask, 1.5, 20); // scale = 1.5 , bins/rotation cap = 20
//
// now we can finally get the homography for the object
//
// if we dont have 4 matches, we cant build homography match
if(count >= 4)
{
homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(targetKeyPoints, sceneKeyPoints, matches, mask,
5); // adding mask will help to bring the best and unique matches - tweak the last peramiter
}
if (homography != null)
{
Rectangle rect = new Rectangle(Point.Empty, target.Size); // draw rectangle same size as the target image
// use homography to tell it where to draw it as it uses relationship between image and keypoints
// make array of the points as that what the transform method takes
PointF[] pts = new PointF[]
{
new PointF(rect.Left, rect.Bottom),
new PointF(rect.Right, rect.Bottom),
new PointF(rect.Right, rect.Top),
new PointF(rect.Left, rect.Top)
};
pts = CvInvoke.PerspectiveTransform(pts, homography); // put it into the pts
Point[] points = Array.ConvertAll<PointF, Point>(pts, Point.Round); // transform into vectorofpoints array to return
pointsToReturn = new VectorOfPoint(points);
}
return pointsToReturn;
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
}
}
Then in my main windows form I pass it the target and scene image and call the method to get returned the bitmap to display. But it errors on that specefic line each time:
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.Drawing.Imaging;
using System.Diagnostics;
using Emgu.CV;
using Emgu.CV.Structure;
namespace mine
{
public partial class mainform: Form
{
private Bitmap currentPassedImgBmp;
private void button2_Click_1(object sender, EventArgs e)
{
MyImageProcessing newImgProc = new MyImageProcessing();
Image<Bgr, byte> testTargetImg = new Image<Bgr, byte>(@"C:\items\target.png");
Image<Bgr, byte> sourceImgFromBMP = new Image<Bgr, byte>(@"C:\items\searchref.png");
// Image<Bgr, byte> sourceImgFromBMP = currentPassedImgBmp.ToImage<Bgr, byte>();
var mybitmap = newImgProc.findImgFB(sourceImgFromBMP, testTargetImg);
}
}
}
Any guidance or pointing in the right direction would help, I have spent nearly a whole day on this going through different answers and tutorials, which are either outdated or referring to videos which changes the context it seems.
Upvotes: 0
Views: 945
Reputation: 101
I did not test my proposed solution, but am pretty confident that you need to initialize matches before passing it to the KnnMatch method:
VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch();
I would also point out, that you need to take care to properly dispose objects holding unmanaged resources (e.g. EmguCV's Mat objects), otherwise you'll quickly run into memory issues once you get beyond the step of experimentation.
Upvotes: 1