eclipse240hp
New member
Ich arbeite an einer augmented reality App für den Browser welcher einen QR Code erkennt, der auf einem DIN A4 Blatt ausgedruckt ist und dadurch ein Objekt in den Raum projeziert.
Ich habe im Internet eine fertige Lösung gefunden, die auf ARUCO codes basiert, aber für meinen Zweck benötige ich die Erkennung der Konturen eines QR Codes, da diese gröber sind und auch von größeren Entfernungen (z.B. 3 Meter) erkannt werden.
Hier geht es nicht um das auslesen eines QR codes, sondern nur um die Feststellung der Position.
Ich habe eine Lösung gefunden, die die Konturen des QR Codes erkennt, diese ist aber auf C++ geschrieben und ich habe versucht das Script auf JavaScript umzuschreiben.
Das ist die Lösung mit den ARUCO Codes die in JavaScript geschrieben ist und super funktioniert.
var JS = Augmented Reality in Three.js
Das ist das Script dafür: https://github.com/jeromeetienne/arplayerforthreejs
Das ist das C++ Script, welches QR Codes erkennt:
var C++ = https://github.com/xingdi-eric-yuan/qr-decoder
Soweit habe ich die Logik des C++ Scriptes umgeschrieben, dass mein Programm bereits die 3 Erkennungspunkte des QR Codes feststellen sollte und in die Variable this.vecpair; schreibt.
Leider werden aber Keine 3 festgestellte Konturpaare ausgegeben...
Die Funktion zum analysieren nach QR Codes wird in der Datei "threex.jsarucomarker.js" mit QR.Detector(); aufgerufen und liefert die Konturpaare.
Und das ist meine bisherige Lösung die noch nicht ganz fertig ist aber dennoch schon den QR Code erkennen sollte.. Das Script ist ein Mix aus der ARUCO Lösung "aruco.js" und dem C++ Script qrdecoder.cpp
Die folgenden Funktionen sind meine erstellten CV Funktionen die in der "cv.js" (https://github.com/jeromeetienne/arplayerforthreejs) enthalten sind und die Originalen OpenCV Funktionen "darstellen".
Eventuell scheitert es bei der Analyse ja an dieser Stelle...
Diese Funktionen sollten die selbe Funktion haben wie bei OpenCV in C++
pointPolygonTest() = Point Polygon Test — OpenCV 2.4.13.1 documentation
contourArea() = Structural Analysis and Shape Descriptors — OpenCV 2.4.13.1 documentation
Vielen Dank für jede Hilfe!
Vielleicht schaffen wir es ja zusammen das ganze zum Laufen zu bringen
Ich habe im Internet eine fertige Lösung gefunden, die auf ARUCO codes basiert, aber für meinen Zweck benötige ich die Erkennung der Konturen eines QR Codes, da diese gröber sind und auch von größeren Entfernungen (z.B. 3 Meter) erkannt werden.
Hier geht es nicht um das auslesen eines QR codes, sondern nur um die Feststellung der Position.
Ich habe eine Lösung gefunden, die die Konturen des QR Codes erkennt, diese ist aber auf C++ geschrieben und ich habe versucht das Script auf JavaScript umzuschreiben.
Das ist die Lösung mit den ARUCO Codes die in JavaScript geschrieben ist und super funktioniert.
var JS = Augmented Reality in Three.js
Das ist das Script dafür: https://github.com/jeromeetienne/arplayerforthreejs
Das ist das C++ Script, welches QR Codes erkennt:
var C++ = https://github.com/xingdi-eric-yuan/qr-decoder
Soweit habe ich die Logik des C++ Scriptes umgeschrieben, dass mein Programm bereits die 3 Erkennungspunkte des QR Codes feststellen sollte und in die Variable this.vecpair; schreibt.
Leider werden aber Keine 3 festgestellte Konturpaare ausgegeben...
Die Funktion zum analysieren nach QR Codes wird in der Datei "threex.jsarucomarker.js" mit QR.Detector(); aufgerufen und liefert die Konturpaare.
Und das ist meine bisherige Lösung die noch nicht ganz fertig ist aber dennoch schon den QR Code erkennen sollte.. Das Script ist ein Mix aus der ARUCO Lösung "aruco.js" und dem C++ Script qrdecoder.cpp
Code:
var QR = QR || {};
QR.Marker = function(id, corners){
this.id = id;
this.corners = corners;
};
QR.Detector = function(){
this.grey = new CV.Image();
this.thres = new CV.Image();
this.homography = new CV.Image();
this.binary = [];
this.cont = [];
this.vec4i = [];
this.contours = this.cont.contours = [];
};
QR.Detector.prototype.detect = function(image){
CV.grayscale(image, this.grey);
CV.adaptiveThreshold(this.grey, this.thres, 2, 7);
this.contours = CV.findContours(this.thres, this.binary);
//this.contours = this.findLimitedConturs(this.thres, 8.00, 0.2 * image.width * image.height);
// console.log(this.contours);
this.vecpair = this.getContourPair(this.contours);
console.log(this.vecpair);
// ARUCO CODE.. MAYBE NOT NECESSARY
//this.candidates = this.findCandidates(this.contours, image.width * 0.10, 0.05, 10);
//this.candidates = this.clockwiseCorners(this.candidates);
//this.candidates = this.notTooNear(this.candidates, 10);
//return this.findMarkers(this.grey, this.candidates, 49);
};
/* C++
struct FinderPattern{
Point topleft;
Point topright;
Point bottomleft;
FinderPattern(Point a, Point b, Point c) : topleft(a), topright(b), bottomleft(c) {}
};
bool compareContourAreas ( std::vector<cv::Point> contour1, std::vector<cv::Point> contour2 ) {
double i = fabs( contourArea(cv::Mat(contour1)) );
double j = fabs( contourArea(cv::Mat(contour2)) );
return ( i > j );
}
*/
QR.Detector.prototype.compareContourAreas = function(c1,c2){
//console.log('compareContourAreas'+c2);
var i = Math.abs(CV.contourArea(c1));
var j = Math.abs(CV.contourArea(c2));
if(i > j){
return true;
}
return false;
};
/* C++
Point getContourCentre(CONT& vec){
double tempx = 0.0, tempy = 0.0;
for(int i=0; i<vec.size(); i++){
tempx += vec[i].x;
tempy += vec[i].y;
}
return Point(tempx / (double)vec.size(), tempy / (double)vec.size());
}
*/
QR.Detector.prototype.getContourCentre = function(vec){
};
/* C++
bool isContourInsideContour(CONT& in, CONT& out){
for(int i = 0; i<in.size(); i++){
if(pointPolygonTest(out, in[i], false) <= 0) return false;
}
return true;
}
*/
QR.Detector.prototype.isContourInsideContour = function(c_in, c_out){
for(var i = 0; i<c_in.length; i++){
//console.log('-- '+c_out+' -- '+c_in[i]);
if(CV.pointPolygonTest(c_out, c_in[i]) == false) return false;
}
console.log('c in c!!');
return true;
};
/* C++
vector<CONT > findLimitedConturs(Mat contour, float minPix, float maxPix){
vector<CONT > contours;
vector<Vec4i> hierarchy;
findContours(contour, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
cout<<"contours.size = "<<contours.size()<<endl;
int m = 0;
while(m < contours.size()){
if(contourArea(contours[m]) <= minPix){
contours.erase(contours.begin() + m);
}else if(contourArea(contours[m]) > maxPix){
contours.erase(contours.begin() + m);
}else ++ m;
}
cout<<"contours.size = "<<contours.size()<<endl;
return contours;
}
*/
QR.Detector.prototype.findLimitedConturs = function(contour, minPix, maxPix){
this.contours = this.cont.contours = [];
this.hierarchy = this.vec4i.hierarchy = [];
CV.findContours(contour, this.contours);
// console.log(this.contours);
var m = 0;
while(m < this.contours.length){
if(CV.contourArea(this.contours[m]) <= minPix){
this.contours.splice(this.contours[0] + m,1);
}else if(CV.contourArea(this.contours[m]) > maxPix){
this.contours.splice(this.contours[0] + m,1);
}else ++ m;
}
// console.log(this.contours.length);
return this.contours;
};
/*
vector<vector<CONT > > getContourPair(vector<CONT > &contours){
vector<vector<CONT > > vecpair;
vector<bool> bflag(contours.size(), false);
for(int i = 0; i<contours.size() - 1; i++){
if(bflag[i]) continue;
vector<CONT > temp;
temp.push_back(contours[i]);
for(int j = i + 1; j<contours.size(); j++){
if(isContourInsideContour(contours[j], contours[i])){
temp.push_back(contours[j]);
bflag[j] = true;
}
}
if(temp.size() > 1){
vecpair.push_back(temp);
}
}
bflag.clear();
for(int i=0; i<vecpair.size(); i++){
sort(vecpair[i].begin(), vecpair[i].end(), compareContourAreas);
}
return vecpair;
}
*/
QR.Detector.prototype.getContourPair = function(contours){
this.vecpair = this.cont.vecpair = [];
var bflag = new Array(); // similar to c++: vector<bool> bflag(contours.size(), false);?
for(var i = 0; i<contours.length - 1; i++){
bflag[i] = false;
}
//console.log(bflag);
for(var i = 0; i<contours.length - 1; i++){
if(bflag[i] == false){ //similar to c++: if(bflag[i]) continue; ??
var temp = this.cont.temp = [];
//console.log(contours[i]);
temp.push(contours[i]); //similar to c++: temp.push_back(contours[i]); ??
for(var j = i + 1; j<contours.length; j++){
if(this.isContourInsideContour(contours[j], contours[i])){
temp.push(contours[j]);
bflag[j] = true;
}
}
if(temp.length > 1){
this.vecpair.push(temp);
}
}
}
//console.log(this.vecpair);
bflag = [];
for(i=0; i<this.vecpair.length; i++){
// sort(this.vecpair[0], this.vecpair[this.vecpair.length], compareContourAreas);
this.vecpair.sort(function(a,b){
return a-b;
});
//console.log('start --- '+this.vecpair[i][0]);
//console.log('end ---'+this.vecpair[i][this.vecpair[i].length-1]);
console.log('org: '+this.vecpair.length);
//console.log(this.compareContourAreas(this.vecpair[i][0], this.vecpair[i][this.vecpair[i].length-1]));
if(this.compareContourAreas(this.vecpair[i][0], this.vecpair[i][this.vecpair[i].length-1]) == false)
{
this.vecpair[1].slice();
}
console.log('after compare : '+this.vecpair.length);
// console.log(this.vecpair);
}
//console.log(this.vecpair);
return this.vecpair;
};
/* C++
void eliminatePairs(vector<vector<CONT > >& vecpair, double minRatio, double maxRatio){
cout<<"maxRatio = "<<maxRatio<<endl;
int m = 0;
bool flag = false;
while(m < vecpair.size()){
flag = false;
if(vecpair[m].size() < 3){
vecpair.erase(vecpair.begin() + m);
continue;
}
for(int i=0; i<vecpair[m].size() - 1; i++){
double area1 = contourArea(vecpair[m][i]);
double area2 = contourArea(vecpair[m][i + 1]);
if(area1 / area2 < minRatio || area1 / area2 > maxRatio){
vecpair.erase(vecpair.begin() + m);
flag = true;
break;
}
}
if(!flag){
++ m;
}
}
if(vecpair.size() > 3){
eliminatePairs(vecpair, minRatio, maxRatio * 0.9);
}
}
*/
QR.Detector.prototype.eliminatePairs = function(){};
/* C++
double getDistance(Point a, Point b){
return sqrt(pow((a.x - b.x), 2) + pow((a.y - b.y), 2));
}
*/
QR.Detector.prototype.getDistance = function(){};
/* C++
FinderPattern getFinderPattern(vector<vector<CONT > > &vecpair){
Point pt1 = getContourCentre(vecpair[0][vecpair[0].size() - 1]);
Point pt2 = getContourCentre(vecpair[1][vecpair[1].size() - 1]);
Point pt3 = getContourCentre(vecpair[2][vecpair[2].size() - 1]);
double d12 = getDistance(pt1, pt2);
double d13 = getDistance(pt1, pt3);
double d23 = getDistance(pt2, pt3);
double x1, y1, x2, y2, x3, y3;
double Max = max(d12, max(d13, d23));
Point p1, p2, p3;
if(Max == d12){
p1 = pt1;
p2 = pt2;
p3 = pt3;
}else if(Max == d13){
p1 = pt1;
p2 = pt3;
p3 = pt2;
}else if(Max == d23){
p1 = pt2;
p2 = pt3;
p3 = pt1;
}
x1 = p1.x;
y1 = p1.y;
x2 = p2.x;
y2 = p2.y;
x3 = p3.x;
y3 = p3.y;
if(x1 == x2){
if(y1 > y2){
if(x3 < x1){
return FinderPattern(p3, p2, p1);
}else{
return FinderPattern(p3, p1, p2);
}
}else{
if(x3 < x1){
return FinderPattern(p3, p1, p2);
}else{
return FinderPattern(p3, p2, p1);
}
}
}else{
double newy = (y2 - y1) / (x2 - x1) * x3 + y1 - (y2 - y1) / (x2 - x1) * x1;
if(x1 > x2){
if(newy < y3){
return FinderPattern(p3, p2, p1);
}else{
return FinderPattern(p3, p1, p2);
}
}else{
if(newy < y3){
return FinderPattern(p3, p1, p2);
}else{
return FinderPattern(p3, p2, p1);
}
}
}
}
*/
QR.Detector.prototype.getFinderPattern = function(){};
Die folgenden Funktionen sind meine erstellten CV Funktionen die in der "cv.js" (https://github.com/jeromeetienne/arplayerforthreejs) enthalten sind und die Originalen OpenCV Funktionen "darstellen".
Eventuell scheitert es bei der Analyse ja an dieser Stelle...
Diese Funktionen sollten die selbe Funktion haben wie bei OpenCV in C++
pointPolygonTest() = Point Polygon Test — OpenCV 2.4.13.1 documentation
contourArea() = Structural Analysis and Shape Descriptors — OpenCV 2.4.13.1 documentation
Code:
//src: http://jsfromhell.com/math/is-point-in-poly
CV.pointPolygonTest = function(poly, pt){
for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y))
&& (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x)
&& (c = !c);
return c;
};
//http://stackoverflow.com/questions/16285134/calculating-polygon-area
CV.contourArea = function(cont){
//console.log('cont: '+cont);
var area = 0; // Accumulates area in the loop
var j = cont.length-1; // The last vertex is the 'previous' one to the first
for (var i=0; i<cont.length; i++)
{
area = area + (cont[j].x+cont[i].x) * (cont[j].y+cont[i].y)
//area = area + (X[j]+X[i]) * (Y[j]-Y[i]);
j = i; //j is previous vertex to i
}
return area/2;
};
Vielen Dank für jede Hilfe!
Vielleicht schaffen wir es ja zusammen das ganze zum Laufen zu bringen
Zuletzt bearbeitet: