opencvjava:从图像中提取卡片
我正在尝试使用OpenCV和Java实现一些图像处理,以从图像中提取卡片 我的做法如下:opencvjava:从图像中提取卡片,java,opencv,image-processing,Java,Opencv,Image Processing,我正在尝试使用OpenCV和Java实现一些图像处理,以从图像中提取卡片 我的做法如下: 转换为BGR图像 转换为灰度图像 应用高斯模糊 应用Canny边缘检测 扩张 寻找轮廓 找到最大的轮廓 使用APROXPOLYDP查找最大轮廓的角点 沿最大轮廓获取裁剪图像的自顶向下视图 在步骤8中,我面临一些问题,因为我没有获得适当的角点/顶点。以下示例图像显示了该场景: 原始图像 经过边缘检测和膨胀(如何获得适当的边?这里我有断裂的边。无法使Hough变换工作) 在找到顶点之后。(以绿色显示) 代
System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
//load Image
File input = new File("card4.png");
BufferedImage image = ImageIO.read(input);
byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
//put read image to Mat
mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3); //original Mat
mat.put(0, 0, data);
mat_f = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3); //for storing manipulated Mat
//conversion to grayscale, blurring and edge detection
Imgproc.cvtColor(mat, mat_f, Imgproc.COLOR_RGB2BGR);
Imgproc.cvtColor(mat_f, mat_f, Imgproc.COLOR_RGB2GRAY);
Imgproc.GaussianBlur(mat_f, mat_f, new Size(13,13), 0);
Imgproc.Canny(mat_f, mat_f, 300, 600, 5, true);
Imgproc.dilate(mat_f, mat_f, new Mat(), new Point(-1, -1), 2);
Imgcodecs.imwrite("D:\\JAVA\\Image_Proc\\CVTest1.jpg",mat_f);
//finding contours
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat();
Imgproc.findContours(mat_f, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
double maxArea=0;
int maxAreaIdx=0;
//finding largest contour
for (int idx = 0; idx != contours.size(); ++idx)
{
Mat contour = contours.get(idx);
double contourarea = Imgproc.contourArea(contour);
if (contourarea > maxArea)
{
maxArea = contourarea;
maxAreaIdx = idx;
}
}
//Rect rect = Imgproc.boundingRect(contours.get(maxAreaIdx));
//Imgproc.rectangle(mat, new Point(rect.x,rect.y), new Point(rect.x+rect.width,rect.y+rect.height),new Scalar(0,0,255),7);
// mat = mat.submat(rect.y, rect.y + rect.height, rect.x, rect.x + rect.width);
//Polygon approximation
MatOfPoint2f approxCurve = new MatOfPoint2f();
MatOfPoint2f oriCurve = new MatOfPoint2f(contours.get(maxAreaIdx).toArray());
Imgproc.approxPolyDP(oriCurve, approxCurve, 6.0, true);
//drawing red markers at vertices
Point [] array = approxCurve.toArray();
for(int i=0; i < array.length;i++) {
Imgproc.circle(mat, array[i], 2, new Scalar(0, 255, 0), 5);
}
Imgcodecs.imwrite("D:\\JAVA\\Image_Proc\\CVTest.jpg",mat);
System.loadLibrary(Core.NATIVE\u LIBRARY\u NAME);
//加载图像
文件输入=新文件(“card4.png”);
BuffereImage image=ImageIO.read(输入);
字节[]数据=((DataBufferByte)image.getRaster().getDataBuffer()).getData();
//将读取的图像放到垫子上
mat=新mat(image.getHeight()、image.getWidth()、CvType.CV_8UC3)//原垫
材料放置(0,0,数据);
mat_f=新mat(image.getHeight()、image.getWidth()、CvType.CV_8UC3)//用于存放被操纵的垫子
//转换为灰度、模糊和边缘检测
Imgproc.cvt颜色(mat,mat_f,Imgproc.COLOR_RGB2BGR);
Imgproc.cvt颜色(mat\u f、mat\u f、Imgproc.COLOR\u RGB2GRAY);
GaussianBlur(mat_f,mat_f,新尺寸(13,13),0);
Imgproc.Canny(mat_f,mat_f,300600,5,true);
Imgproc.deplate(mat_f,mat_f,new mat(),new Point(-1,-1),2);
Imgcodecs.imwrite(“D:\\JAVA\\Image\u Proc\\CVTest1.jpg”,mat\u f);
//寻找等高线
列表等高线=新的ArrayList();
Mat层次结构=新Mat();
Imgproc.findContours(材质、轮廓、层次、Imgproc.RETR\u外部、Imgproc.CHAIN\u近似\u简单);
双最大面积=0;
int maxAreaIdx=0;
//寻找最大等高线
对于(int idx=0;idx!=courts.size();++idx)
{
Mat contour=contours.get(idx);
双轮廓面积=Imgproc.轮廓面积(轮廓);
如果(轮廓面积>最大面积)
{
最大面积=轮廓面积;
maxAreaIdx=idx;
}
}
//Rect Rect=Imgproc.boundingRect(contours.get(maxAreaIdx));
//Imgproc.矩形(mat,新点(rect.x,rect.y),新点(rect.x+rect.width,rect.y+rect.height),新标量(0,0255),7);
//mat=mat.submat(矩形y,矩形y+矩形高度,矩形x,矩形x+矩形宽度);
//多边形近似
MatOfPoint2f approxCurve=新的MatOfPoint2f();
MatOfPoint2f oriCurve=新的MatOfPoint2f(courts.get(maxAreaIdx.toArray());
Imgproc.approxPolyDP(oriCurve,approxCurve,6.0,true);
//在顶点处绘制红色标记
点[]数组=approxCurve.toArray();
for(int i=0;i
正在寻求帮助以获取适当的角点顶点。。。
提前感谢。为了使用您的方法归档好的结果,您的卡必须包含4个角。但我更喜欢使用HoughLine方法完成此任务。
步骤1:调整图像大小以获得更高的性能
步骤2:边缘检测
- 将图像转换为灰度
- 模糊图像以清除噪声
- 基于Canny滤波器的边缘检测
第三步:找到卡片的角落
- 寻找图像的轮廓
- 从轮廓列表中获得最大轮廓
- 抓住它
- 使用APROXPOLYDP简化凸面外壳(这将给出一个四边形)
- 从现在开始,您可以绘制等高线,以获得恢复比例后的矩形
- 从四边形可以得到4个角
- 查找单应性
- 使用计算的单应矩阵扭曲输入图像
// STEP 1: Resize input image to img_proc to reduce computation
double ratio = DOWNSCALE_IMAGE_SIZE / Math.max(frame.width(), frame.height());
Size downscaledSize = new Size(frame.width() * ratio, frame.height() * ratio);
Mat dst = new Mat(downscaledSize, frame.type());
Imgproc.resize(frame, dst, downscaledSize);
Mat grayImage = new Mat();
Mat detectedEdges = new Mat();
// STEP 2: convert to grayscale
Imgproc.cvtColor(dst, grayImage, Imgproc.COLOR_BGR2GRAY);
// STEP 3: try to filter text inside document
Imgproc.medianBlur(grayImage, detectedEdges, 9);
// STEP 4: Edge detection
Mat edges = new Mat();
// Imgproc.erode(edges, edges, new Mat());
// Imgproc.dilate(edges, edges, new Mat(), new Point(-1, -1), 1); // 1
// canny detector, with ratio of lower:upper threshold of 3:1
Imgproc.Canny(detectedEdges, edges, this.threshold.getValue(), this.threshold.getValue() * 3, 3, true);
// STEP 5: makes the object in white bigger to join nearby lines
Imgproc.dilate(edges, edges, new Mat(), new Point(-1, -1), 1); // 1
Image imageToShow = Utils.mat2Image(edges);
updateImageView(cannyFrame, imageToShow);
// STEP 6: Compute the contours
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(edges, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
// STEP 7: Sort the contours by length and only keep the largest one
MatOfPoint largestContour = getMaxContour(contours);
// STEP 8: Generate the convex hull of this contour
Mat convexHullMask = Mat.zeros(frame.rows(), frame.cols(), frame.type());
MatOfInt hullInt = new MatOfInt();
Imgproc.convexHull(largestContour, hullInt);
MatOfPoint hullPoint = OpenCVUtil.getNewContourFromIndices(largestContour, hullInt);
// STEP 9: Use approxPolyDP to simplify the convex hull (this should give a quadrilateral)
MatOfPoint2f polygon = new MatOfPoint2f();
Imgproc.approxPolyDP(OpenCVUtil.convert(hullPoint), polygon, 20, true);
List<MatOfPoint> tmp = new ArrayList<>();
tmp.add(OpenCVUtil.convert(polygon));
restoreScaleMatOfPoint(tmp, ratio);
Imgproc.drawContours(convexHullMask, tmp, 0, new Scalar(25, 25, 255), 2);
// Image extractImageToShow = Utils.mat2Image(convexHullMask);
// updateImageView(extractFrame, extractImageToShow);
MatOfPoint2f finalCorners = new MatOfPoint2f();
Point[] tmpPoints = polygon.toArray();
for (Point point : tmpPoints) {
point.x = point.x / ratio;
point.y = point.y / ratio;
}
finalCorners.fromArray(tmpPoints);
boolean clockwise = true;
double currentThreshold = this.threshold.getValue();
if (finalCorners.toArray().length == 4) {
Size size = getRectangleSize(finalCorners);
Mat result = Mat.zeros(size, frame.type());
// STEP 10: Homography: Use findHomography to find the affine transformation of your paper sheet
Mat homography = new Mat();
MatOfPoint2f dstPoints = new MatOfPoint2f();
Point[] arrDstPoints = { new Point(result.cols(), result.rows()), new Point(0, result.rows()), new Point(0, 0), new Point(result.cols(), 0) };
dstPoints.fromArray(arrDstPoints);
homography = Calib3d.findHomography(finalCorners, dstPoints);
// STEP 11: Warp the input image using the computed homography matrix
Imgproc.warpPerspective(frame, result, homography, size);
}
//步骤1:将输入图像调整为img_proc以减少计算量
双倍比率=缩尺\图像\大小/Math.max(frame.width(),frame.height());
尺寸缩小尺寸=新尺寸(框宽()*比率,框高()*比率);
Mat dst=新Mat(缩小尺寸,frame.type());
Imgproc.resize(帧、dst、缩小尺寸);
Mat grayImage=新Mat();
Mat DetectedEdge=新Mat();
//步骤2:转换为灰度
Imgproc.cvt颜色(dst、灰度图像、Imgproc.COLOR_bgr2灰度);
//步骤3:尝试筛选文档中的文本
Imgproc.medianBlur(灰度图像,检测到的边缘,9);
//步骤4:边缘检测
垫边=新垫();
//侵蚀(边缘,边缘,新垫());
//Imgproc.deflate(边,边,新垫(),新点(-1,-1),1);//1.
//canny检测器,下限与上限阈值之比为3:1
Canny(detectedEdges,edges,this.threshold.getValue(),this.threshold.getValue()*3,3,true);
//步骤5:使白色的对象变大以连接附近的线
Imgproc.deflate(边,边,新垫(),新点(-1,-1),1);//1.
Image imagestoshow=Utils.mat2Image(边缘);
更新图像视图(cannyFrame,imageToShow);
//步骤6:计算轮廓
列表等高线=新的ArrayList();
Imgproc.findContours(边、轮廓、新垫()、Imgproc.RETR\u列表、Imgproc.CHAIN\u近似值\u简单值);
//步骤7:按长度对轮廓进行排序,只保留最大的轮廓
最大轮廓点=g