Ich arbeite an einer Implementierung, bei der ich ein rechteckförmiges Bild in einem großen Hintergrundbild habe. Ich versuche, das rechteckförmige Bild aus dem großen Bild zu extrahieren und Textinformationen aus diesem bestimmten Rechteckbild abzurufen. Ich versuche, das Open-CV-Drittanbieterframework zu verwenden, konnte aber das Rechteckbild nicht aus dem großen Hintergrundbild extrahieren. Könnte mir jemand bitte sagen, wie ich das erreichen kann?
Aktualisiert:
Ich habe den Link gefunden, um mit OpenCV quadratische Formen zu finden. Kann ich ihn für die Suche nach Rechtecken modifizieren? Kann mir jemand dabei helfen?
NEUESTES UPDATE:
Ich habe den Code schließlich gefunden, hier ist er unten.
- (cv::Mat)cvMatWithImage:(UIImage *)image
{
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
CGFloat cols = image.size.width;
CGFloat rows = image.size.height;
cv::Mat cvMat(rows, cols, CV_8UC4); // 8 Bits pro Komponente, 4 Kanäle
CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Zeiger auf Datenspeicher
cols, // Breite des Bitmaps
rows, // Höhe des Bitmaps
8, // Bits pro Komponente
cvMat.step[0], // Bytes pro Zeile
colorSpace, // Farbraum
kCGImageAlphaNoneSkipLast |
kCGBitmapByteOrderDefault); // Bitmap-Infobits
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage);
CGContextRelease(contextRef);
return cvMat;
}
-(UIImage *)UIImageFromCVMat:(cv::Mat)cvMat
{
NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];
CGColorSpaceRef colorSpace;
if ( cvMat.elemSize() == 1 ) {
colorSpace = CGColorSpaceCreateDeviceGray();
}
else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
//CFDataRef data;
CGDataProviderRef provider = CGDataProviderCreateWithCFData( (CFDataRef) data ); // Es sollte (__bridge CFDataRef)data sein
CGImageRef imageRef = CGImageCreate( cvMat.cols, cvMat.rows, 8, 8 * cvMat.elemSize(), cvMat.step[0], colorSpace, kCGImageAlphaNone|kCGBitmapByteOrderDefault, provider, NULL, false, kCGRenderingIntentDefault );
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease( imageRef );
CGDataProviderRelease( provider );
CGColorSpaceRelease( colorSpace );
return finalImage;
}
-(void)forOpenCV
{
imageView = [UIImage imageNamed:@"myimage.jpg"];
if( imageView != nil )
{
cv::Mat tempMat = [imageView CVMat];
cv::Mat greyMat = [self cvMatWithImage:imageView];
cv::vector > squares;
cv::Mat img= [self debugSquares: squares: greyMat];
imageView = [self UIImageFromCVMat: img];
self.imageView.image = imageView;
}
}
double angle( cv::Point pt1, cv::Point pt2, cv::Point pt0 ) {
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
- (cv::Mat) debugSquares: (std::vector >) squares : (cv::Mat &)image
{
NSLog(@"%lu",squares.size());
// Unschärfe verbessert Kantenerkennung
//cv::Mat blurred(image);
cv::Mat blurred = image.clone();
medianBlur(image, blurred, 9);
cv::Mat gray0(image.size(), CV_8U), gray;
cv::vector > contours;
// Rechtecke in jeder Farbebene des Bildes finden
for (int c = 0; c < 3; c++)
{
int ch[] = {c, 0};
mixChannels(&image, 1, &gray0, 1, ch, 1);
// Verschiedene Schwellenwerte ausprobieren
const int threshold_level = 2;
for (int l = 0; l < threshold_level; l++)
{
// Canny anstelle von Null-Schwellenwert verwenden!
// Canny hilft bei der Erkennung von Quadraten mit Gradientenschattierung
if (l == 0)
{
Canny(gray0, gray, 10, 20, 3); //
// Dilatation hilft, potenzielle Löcher zwischen Kantenabschnitten zu entfernen
dilate(gray, gray, cv::Mat(), cv::Point(-1,-1));
}
else
{
gray = gray0 >= (l+1) * 255 / threshold_level;
}
// Konturen finden und in einer Liste speichern
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
// Konturen überprüfen
cv::vector approx;
for (size_t i = 0; i < contours.size(); i++)
{
// Kontur annähernd mit Genauigkeit proportional
// zum Umfang der Kontur
approxPolyDP(cv::Mat(contours[i]), approx, arcLength(cv::Mat(contours[i]), true)*0.02, true);
// Hinweis: Der absolute Wert einer Fläche wird verwendet, da
// die Fläche positiv oder negativ sein kann - entsprechend der
// Konturorientierung
if (approx.size() == 4 &&
fabs(contourArea(cv::Mat(approx))) > 1000 &&
isContourConvex(cv::Mat(approx)))
{
double maxCosine = 0;
for (int j = 2; j < 5; j++)
{
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
maxCosine = MAX(maxCosine, cosine);
}
if (maxCosine < 0.3)
squares.push_back(approx);
}
}
}
}
NSLog(@"squares.size(): %lu");
for( size_t i = 0; i < squares.size(); i++ )
{
cv::Rect rectangle = boundingRect(cv::Mat(squares[i]));
NSLog(@"rectangle.x: %d", rectangle.x);
NSLog(@"rectangle.y: %d", rectangle.y);
if(i==squares.size()-1)////Hier Rechteck erkennen
{
const cv::Point* p = &squares[i][0];
int n = (int)squares[i].size();
NSLog(@"%d",n);
line(image, cv::Point(507,418), cv::Point(507+1776,418+1372), cv::Scalar(255,0,0),2,8);
polylines(image, &p, &n, 1, true, cv::Scalar(255,255,0), 5, CV_AA);
int fx1=rectangle.x;
NSLog("X: %d", fx1);
int fy1=rectangle.y;
NSLog("Y: %d", fy1);
int fx2=rectangle.x+rectangle.width;
NSLog("Width: %d", fx2);
int fy2=rectangle.y+rectangle.height;
NSLog("Height: %d", fy2);
line(image, cv::Point(fx1,fy1), cv::Point(fx2,fy2), cv::Scalar(0,0,255),2,8);
}
}
return image;
}
Vielen Dank.