public static int ExtractTables(Image img) { //Delete this after Bitmap bit; List <Rectangle> AreasOfInterest = new List <Rectangle>(); Bitmap bitmap = (Bitmap)img; Mat srcImg = OCS.Extensions.BitmapConverter.ToMat(bitmap); if (srcImg.Data == null) { throw new NullReferenceException("Image has nothing?"); } //Resize into smaller size Mat rsz = new Mat(); OpenCvSharp.Size size = new OpenCvSharp.Size(4000, 2828); Cv2.Resize(srcImg, rsz, size); // Convert to greyscale if it has more than one channel // else just leave it alone Mat grey = new Mat(); Cv2.CvtColor(rsz, grey, ColorConversionCodes.BGR2GRAY); #if IMG_DEBUG Cv2.ImShow("grey", grey); Cv2.WaitKey(0); #endif //Apply adaptive thresholding to get negative Mat bw = new Mat(); Cv2.AdaptiveThreshold(~grey, bw, 255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 15, -2); bit = OCS.Extensions.BitmapConverter.ToBitmap(bw); bit.Save("bw.tiff", System.Drawing.Imaging.ImageFormat.Tiff); // Create two new masks cloned from bw. Mat horizontal = bw.Clone(); Mat vertical = bw.Clone(); // adjust this for number of lines int scale = 10; ///////////////////////// ///////////////////////// ///////////////////////// // Specify size on horizontal axis int horizontalsize = horizontal.Cols / scale; // Create structure element for extracting horizontal lines through morphology operations //Mat horizontalStructure = getStructuringElement(MORPH_RECT, Size(horizontalsize, 1)); Mat horizontalStructure = Cv2.GetStructuringElement(MorphShapes.Rect, new OCS.Size(horizontalsize, 1)); // Apply morphology operations //erode(horizontal, horizontal, horizontalStructure, Point(-1, -1)); Cv2.Erode(horizontal, horizontal, horizontalStructure, new OCS.Point(-1, -1)); //dilate(horizontal, horizontal, horizontalStructure, Point(-1, -1)); Cv2.Dilate(horizontal, horizontal, horizontalStructure, new OCS.Point(-1, -1)); // dilate(horizontal, horizontal, horizontalStructure, Point(-1, -1)); // expand horizontal lines // Show extracted horizontal lines #if IMG_DEBUG Cv2.ImShow("horizontal", horizontal); Cv2.WaitKey(0); #endif bit = OCS.Extensions.BitmapConverter.ToBitmap(horizontal); bit.Save("horizontal.tiff", System.Drawing.Imaging.ImageFormat.Tiff); // Specify size on vertical axis int verticalsize = vertical.Rows / scale; // Create structure element for extracting vertical lines through morphology operations //Mat verticalStructure = getStructuringElement(MORPH_RECT, Size(1, verticalsize)); Mat verticalStructure = Cv2.GetStructuringElement(MorphShapes.Rect, new OCS.Size(1, verticalsize)); // Apply morphology operations //erode(vertical, vertical, verticalStructure, Point(-1, -1)); Cv2.Erode(vertical, vertical, verticalStructure, new OCS.Point(-1, -1)); //dilate(vertical, vertical, verticalStructure, Point(-1, -1)); Cv2.Dilate(vertical, vertical, verticalStructure, new OCS.Point(-1, -1)); // Show extracted vertical lines #if IMG_DEBUG Cv2.ImShow("vertical", vertical); Cv2.WaitKey(0); #endif bit = OCS.Extensions.BitmapConverter.ToBitmap(vertical); bit.Save("vertical.tiff", System.Drawing.Imaging.ImageFormat.Tiff); // create a mask which includes the tables Mat mask = horizontal + vertical; #if IMG_DEBUG Cv2.ImShow("mask", mask); Cv2.WaitKey(0); #endif // find the joints between the lines of the tables, we will use this information in order to descriminate tables from pictures (tables will contain more than 4 joints while a picture only 4 (i.e. at the corners)) Mat joints = new Mat(); //bitwise_and(horizontal, vertical, joints); Cv2.BitwiseAnd(horizontal, vertical, joints); //Cv2.ImShow("joints", joints); bit = OCS.Extensions.BitmapConverter.ToBitmap(joints); bit.Save("joints.tiff", System.Drawing.Imaging.ImageFormat.Tiff); #if IMG_DEBUG Cv2.ImShow("a", joints); Cv2.WaitKey(0); #endif //Thread.Sleep(2000); // Find external contours from the mask, which most probably will belong to tables or to images //vector<Vec4i> hierarchy; //std::vector<std::vector<cv::Point>> contours; OCS.HierarchyIndex[] hierarchy; //List<List<OCS.Point>> contours = new List<List<OCS.Point>>; OCS.Point[][] contours; //cv::findContours(mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); Cv2.FindContours(mask, out contours, out hierarchy, OCS.RetrievalModes.External, OCS.ContourApproximationModes.ApproxSimple, new OCS.Point(0, 0)); //////vector<vector<Point>> contours_poly(contours.size() ); //////vector<Rect> boundRect(contours.size() ); //////vector<Mat> rois; List <List <OCS.Point> > contours_poly = new List <List <OCS.Point> >(contours.Length); List <OCS.Rect> boundRect = new List <OCS.Rect>(contours.Length); List <Mat> rois = new List <Mat>(); ////for (size_t i = 0; i < contours.size(); i++) ////{ //// // find the area of each contour //// double area = contourArea(contours[i]); /// //// // // filter individual lines of blobs that might exist and they do not represent a table //// if (area < 100) // value is randomly chosen, you will need to find that by yourself with trial and error procedure //// continue; //// approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true); //// boundRect[i] = boundingRect(Mat(contours_poly[i])); //// // find the number of joints that each table has //// Mat roi = joints(boundRect[i]); //// vector<vector<Point>> joints_contours; //// findContours(roi, joints_contours, RETR_CCOMP, CHAIN_APPROX_SIMPLE); //// // if the number is not more than 5 then most likely it not a table //// if (joints_contours.size() <= 4) //// continue; //// rois.push_back(rsz(boundRect[i]).clone()); //// //drawContours( rsz, contours, i, Scalar(0, 0, 255), CV_FILLED, 8, vector<Vec4i>(), 0, Point() ); //// rectangle(rsz, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 1, 8, 0); ////} for (int i = 0; i < contours.Length; i++) { double area = Cv2.ContourArea(contours[i]); if (area < 100.0) { // Skip because its not likely such a small area is a cell continue; } // contours_poly is null at runtime. so we create a new entry and exit array contours_poly.Add(new List <OCS.Point>()); OutputArray contour_poly_output = OutputArray.Create(contours_poly[i]); InputArray contour_poly_input = InputArray.Create(contours[i]); Cv2.ApproxPolyDP(InputArray.Create(contours[i]), contour_poly_output, 0.0, true); Rect boundingRect = Cv2.BoundingRect(InputArray.Create(contours_poly[i])); boundRect.Add(boundingRect); //boundRect[i] = Cv2.BoundingRect(InputArray.Create(contours_poly[i])); //OCS.Mat roi = Cv2.joints() } #if IMG_DEBUG Cv2.NamedWindow("Output", WindowMode.KeepRatio); Cv2.Rectangle(rsz, boundRect.ElementAt(0), Scalar.Red, 10); Cv2.ImShow("Output", rsz); Cv2.WaitKey(0); Cv2.DestroyAllWindows(); #endif ////for (size_t i = 0; i < rois.size(); ++i) ////{ //// /* Now you can do whatever post process you want //// * with the data within the rectangles/tables. */ //// imshow("roi", rois[i]); //// waitKey(); ////} return(boundRect.Count); }
/// <summary> /// Computes an image descriptor using the set visual vocabulary. /// </summary> /// <param name="image">Image, for which the descriptor is computed.</param> /// <param name="keypoints">Keypoints detected in the input image.</param> /// <param name="imgDescriptor">Computed output image descriptor.</param> /// <param name="pointIdxsOfClusters">pointIdxsOfClusters Indices of keypoints that belong to the cluster. /// This means that pointIdxsOfClusters[i] are keypoint indices that belong to the i -th cluster(word of vocabulary) returned if it is non-zero.</param> /// <param name="descriptors">Descriptors of the image keypoints that are returned if they are non-zero.</param> public void Compute(InputArray image, ref KeyPoint[] keypoints, OutputArray imgDescriptor, out int[][] pointIdxsOfClusters, Mat descriptors = null) { ThrowIfDisposed(); if (image == null) { throw new ArgumentNullException(nameof(image)); } if (imgDescriptor == null) { throw new ArgumentNullException(nameof(imgDescriptor)); } using (var keypointsVec = new VectorOfKeyPoint(keypoints)) using (var pointIdxsOfClustersVec = new VectorOfVectorInt()) { NativeMethods.features2d_BOWImgDescriptorExtractor_compute11(ptr, image.CvPtr, keypointsVec.CvPtr, imgDescriptor.CvPtr, pointIdxsOfClustersVec.CvPtr, Cv2.ToPtr(descriptors)); keypoints = keypointsVec.ToArray(); pointIdxsOfClusters = pointIdxsOfClustersVec.ToArray(); } GC.KeepAlive(image); GC.KeepAlive(imgDescriptor); GC.KeepAlive(descriptors); }
/// <summary> /// /// </summary> /// <param name="indexParams"></param> /// <param name="searchParams"></param> public FlannBasedMatcher(IndexParams indexParams = null, SearchParams searchParams = null) { ptr = NativeMethods.features2d_FlannBasedMatcher_new( Cv2.ToPtr(indexParams), Cv2.ToPtr(searchParams)); }
/// <summary> /// Detect keypoints in an image. /// </summary> /// <param name="image">The image.</param> /// <param name="mask">Mask specifying where to look for keypoints (optional). /// Must be a char matrix with non-zero values in the region of interest.</param> /// <returns>The detected keypoints.</returns> public KeyPoint[] Detect(Mat image, Mat?mask = null) { if (image == null) { throw new ArgumentNullException(nameof(image)); } ThrowIfDisposed(); image.ThrowIfDisposed(); try { using var keyPoints = new VectorOfKeyPoint(); NativeMethods.HandleException( NativeMethods.features2d_Feature2D_detect_Mat1(ptr, image.CvPtr, keyPoints.CvPtr, Cv2.ToPtr(mask))); return(keyPoints.ToArray()); } finally { GC.KeepAlive(this); GC.KeepAlive(image); GC.KeepAlive(mask); } }
/// <summary> /// ウィンドウのプロパティを設定する /// </summary> /// <param name="propId">プロパティの種類</param> /// <param name="propValue">プロパティに設定する値</param> #else /// <summary> /// Set Property of the window /// </summary> /// <param name="propId">Property identifier</param> /// <param name="propValue">New value of the specified property</param> #endif public void SetProperty(WindowProperty propId, double propValue) { Cv2.SetWindowProperty(name, propId, propValue); }
/// <summary> /// ウィンドウのプロパティを取得する /// </summary> /// <param name="propId">プロパティの種類</param> /// <returns>プロパティの値</returns> #else /// <summary> /// Get Property of the window /// </summary> /// <param name="propId">Property identifier</param> /// <returns>Value of the specified property</returns> #endif public double GetProperty(WindowProperty propId) { return(Cv2.GetWindowProperty(name, propId)); }