使用OpenCV检测图像上人物的长方形肖像
我有许多人像肖像的年鉴图像,我正在尝试构建能检测这些肖像的algorytm。至少,要检测正确的矩形肖像。 Example 1Example 2使用OpenCV检测图像上人物的长方形肖像
我试图研究三个方向:
- 人脸检测
- 黑暗矩形检测(自画像是在明亮的背景通常更暗的形状)
- 人们从OCR'ed名称提取文本
通过结合上述三种算法的结果,我希望能得到一些方法,也可以用到对于许多不同的年鉴页面。
我将非常感谢任何帮助矩形检测。 我开始使用Java和OpenCV 3.
这里被应用于an image我的代码:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat source = Imgcodecs.imread("Path/to/image", Imgcodecs.CV_LOAD_IMAGE_ANYCOLOR);
Mat destination = new Mat(source.rows(), source.cols(), source.type());
Imgproc.cvtColor(source, destination, Imgproc.COLOR_RGB2GRAY);
Imgproc.GaussianBlur(destination, destination, new Size(5, 5), 0, 0, Core.BORDER_DEFAULT);
int threshold = 100;
Imgproc.Canny(destination, destination, 50, 100);
Imgproc.Canny(destination, destination, threshold, threshold*3);
试图找到从边缘轮廓以上:
List<MatOfPoint> contourDetections = new ArrayList<>();
Mat hierarchy = new Mat();
// Find contours
Imgproc.findContours(destination, contourDetections, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
// Draw contours
Imgproc.drawContours(source, contours, -1, new Scalar(255,0,0), 2);
但不知道如何从这些轮廓中提取矩形,因为许多行不完整。
Mat lines = new Mat();
int thre = 50;
int minLineSize = 250;
int lineGap = 80;
int ignoreLinesShorter = 300;
Imgproc.HoughLinesP(destination, lines, 1, Math.PI/180, thre, minLineSize, lineGap);
for(int c = 0; c < lines.rows(); c++) {
double[] vec = lines.get(c, 0);
double x1 = vec[0],
y1 = vec[1],
x2 = vec[2],
y2 = vec[3];
// Filtering only verticat and horizontal lines
if(x1 == x2 || y1 == y2) {
// Filtering out short lines
if(Math.abs(x1 - x2) > ignoreLinesShorter || Math.abs(y1 - y2) > ignoreLinesShorter) {
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
// Draw line
Imgproc.line(source, start, end, new Scalar(0,0,255), 2);
}
}
}
结果:使用HoughLinesP
再回到边缘,并试图找到垂直和水平线
用一样的轮廓,我仍然没有看到正确的是矩形我可以检测到。你能帮助我一个正确的方向吗?也许有一个更简单的方法来执行此任务?
这不是一个完整的答案,但可能有用。
我用下面的代码得到下面的图像。
明白,你可以在http://answers.opencv.org/question/85884
参考我以前的答案,如果它似乎有希望,我们会尽量一起提高它的代码。因为边缘是不完整的
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
int main(int argc, char** argv)
{
Mat img = imread("e:/test/twHVm.jpg");
if (img.empty())
return -1;
Mat resized, gray, reduced_h, reduced_w;
resize(img, resized, Size(), 1, 1);
cvtColor(resized, gray, CV_BGR2GRAY);
reduce(gray, reduced_h, 0, REDUCE_AVG);
reduce(gray, reduced_w, 1, REDUCE_AVG);
for (int i = 0; i < img.cols; i++)
{
if (reduced_h.at<uchar>(0, i) > 200) // this is experimental value
line(resized, Point(i, 0), Point(i, img.rows), Scalar(0, 255, 0), 1);
}
for (int i = 0; i < img.rows; i++)
{
if (reduced_w.at<uchar>(i, 0) > 225) // this is experimental value
line(resized, Point(0, i), Point(img.cols, i), Scalar(0, 255, 0), 1);
}
imshow("result", resized);
waitKey(0);
return 0;
}
嗨,曾经在类似的项目上工作。我有一些照片旋转,我不得不让它们看起来很正常(旋转到正常状态)。所以我设法检测它们是水平的还是垂直的并旋转它们。但无法检测到它们是否被镜像 –
您可以通过示例图像和代码提出另一个问题。请让我看看我是否可以帮助您。 – sturkmen
你有一个很好的结果,谢谢。我会看看你的代码。 –
轮廓是不完整的。你在Canny尝试了较低的阈值吗?你也可以用'contourArea'按尺寸过滤较小的轮廓。 –
*如何增加*轮廓的阈值,然后扩展所有的垂直和水平线? –