美文网首页
iOS下使用OpenCV进行图像识别(不使用Haar和LBP,不

iOS下使用OpenCV进行图像识别(不使用Haar和LBP,不

作者: unravelW | 来源:发表于2018-07-30 14:08 被阅读0次

    本文翻译自iOS  Application  Development  with  OpenCV 3

    在OpenCV中我们可以使用大量图片进行机器学习来识别图像,但这同样会花费大量的时间。接下来我们来看一下如何只进行少量的机器训练便可以识别图像。

    我们分为以下5个步骤来进行:

    1、将图像分割为前景和背景区域。前景区域为黑色,背景为白色。

    2、使前景区域边缘更加平滑

    3、检测前景的形状,并裁剪出前景的矩形图像。

    4、对裁剪出来的前景图像进行直方图分析。

    5、对图像进行特征匹配(或叫关键点匹配)

    1、blob detection(将图像分割为前景区域和背景区域)

    通常,一个blob detection需要解决以下几个问题:

    1、Segmentation:区分前景区域和背景区域

    2、Edge  detection:区分边缘部分和不是边缘部分

    3、Contour analysis:简单的代表边缘,以便于我们形成一个几何图形

    我们使用cv::inRang方法来区分前景区域和背景区域,在使用cv::Canny方法来画出边缘部分,最后使用cv::findContours来找到这些轮廓,并使用cv::boundingRect来画出矩形框住这些轮廓。

    2、直方图分析

    直方图是图像中每种颜色出现次数的计数。 通常,我们不会分别计算所有可能的颜色; 相反,我们将相似的颜色组合成一个bin。 对于较少数量的bin,直方图占用较少的内存并提供较粗略的比较基础。 我们选择每个通道32个bin(或总共32 ^ 3 = 32678(bin))。

    直方图的比较可以告诉我们两个图像是否包含相似的颜色。 仅这种相似性并不一定意味着图像包含匹配的对象。 例如,银叉和银币可以具有类似的直方图。

    OpenCV提供函数cv :: calcHist和cv :: compareHist来计算直方图并测量它们的相似性。

    3、特征匹配

    OpenCV提供了SURF detector/extractor配上FLANN matcher,和ORB detector/extractor配上brute-force matcher来实现特征匹配。

    SURF有被申请专利,所以请不要用于商业用途,这个方法在opencv_contrib中通过cv::xfeature2d::SURF实现。如果我们没有导入opencv_contrib的话,我们可以用ORB,这个方法在cv::ORB类中实现。

    以下是项目相关代码

    创建Blob描述

    BlobDescriptor BlobClassifier::createBlobDescriptor(const Blob &blob) const {

          const cv::Mat &mat = blob.getMat();

          int numChannels = mat.channels();

          // Calculate the histogram of the blob's image.

        cv::Mat histogram;

        int channels[] = { 0, 1, 2 };

        int numBins[] = { HISTOGRAM_NUM_BINS_PER_CHANNEL, HISTOGRAM_NUM_BINS_PER_CHANNEL, HISTOGRAM_NUM_BINS_PER_CHANNEL };

        float range[] = { 0.0f, 256.0f };

        const float *ranges[] = { range, range, range };

        cv::calcHist(&mat, 1, channels, cv::Mat(), histogram, 3, numBins, ranges);

        // Normalize the histogram.

        histogram *= (1.0f / (mat.rows * mat.cols));

        // Convert the blob's image to grayscale.

         cv::Mat grayMat; switch (numChannels) {

                    case 4:

                              cv::cvtColor(mat, grayMat, cv::COLOR_BGRA2GRAY);

                               break;

                    default:

                               cv::cvtColor(mat, grayMat, cv::COLOR_BGR2GRAY);

                                break;

              }

                // Adaptively equalize the grayscale image to enhance local contrast.  

                clahe->apply(grayMat, grayMat);

                 // Detect features in the grayscale image. std::vector keypoints;     

                 featureDetectorAndDescriptorExtractor->detect(grayMat, keypoints);

                  // Extract descriptors of the features.

                    cv::Mat<cv::KeyPoint> keypointDescriptors;

                    featureDetectorAndDescriptorExtractor->compute(grayMat, keypoints, keypointDescriptors);

                    return BlobDescriptor(histogram, keypointDescriptors, blob.getLabel());

    }

    计算两个Blob之间的Distance

    float BlobClassifier::findDistance(const BlobDescriptor &detectedBlobDescriptor, const BlobDescriptor &referenceBlobDescriptor) const {

             // Calculate the histogram distance.

             float histogramDistance = (float)cv::compareHist(detectedBlobDescriptor.getNormalizedHistogram(), referenceBlobDescriptor.getNormalizedHistogram(), HISTOGRAM_COMPARISON_METHOD);

             // Calculate the keypoint matching distance.

             float keypointMatchingDistance = 0.0f;

              std::vector<cv::DMatch> keypointMatches;

        descriptorMatcher->match(detectedBlobDescriptor.getKeypointDescriptors(), referenceBlobDescriptor.getKeypointDescriptors(), keypointMatches);

             for (const cv::DMatch &keypointMatch : keypointMatches) {

            keypointMatchingDistance += keypointMatch.distance;

        }

        return histogramDistance * HISTOGRAM_DISTANCE_WEIGHT + keypointMatchingDistance * KEYPOINT_MATCHING_DISTANCE_WEIGHT;

    }

    检测Blob

    void BlobDetector::detect(cv::Mat &image, std::vector<Blob> &blobs, double resizeFactor, bool draw){         

               blobs.clear();

               if (resizeFactor == 1.0) {

                             createMask(image);

               } else {

                       cv::resize(image, resizedImage, cv::Size(), resizeFactor, resizeFactor, cv::INTER_AREA);

                       createMask(resizedImage);

                }

               // Find the edges in the mask.

               cv::Canny(mask, edges, 191, 255);

                // Find the contours of the edges.

                 cv::findContours(edges, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

                 std::vector <cv::Rect>  rects;

                 int blobMinSize = (int)(MIN(image.rows, image.cols) * BLOB_RELATIVE_MIN_SIZE_IN_IMAGE);

                for (std::vector<cv::Point> contour : contours) {

                            // Find the contour's bounding rectangle.

                            cv::Rect rect = cv::boundingRect(contour);

                           // Restore the bounding rectangle to the original scale.

                           rect.x /= resizeFactor;

                            rect.y /= resizeFactor;

                           rect.width /= resizeFactor;

                            rect.height /= resizeFactor;

                           if (rect.width < blobMinSize || rect.height < blobMinSize) {

                                     continue;

                          }

                          // Create the blob from the sub-image inside the bounding rectangle.

                           blobs.push_back(Blob(cv::Mat(image, rect)));

                           // Remember the bounding rectangle in order to draw it later.

                          rects.push_back(rect);

              }

               if (draw) {

                      // Draw the bounding rectangles.

                         for (const cv::Rect &rect : rects) {

                        cv::rectangle(image, rect.tl(), rect.br(), DRAW_RECT_COLOR);

                  }

        }

    }

    创建mask

    void BlobDetector::createMask(const cv::Mat &image) {

        // Find the image's mean color.

        // Presumably, this is the background color.

        // Also find the standard deviation.

        cv::Scalar meanColor;

        cv::Scalar stdDevColor;

        cv::meanStdDev(image, meanColor, stdDevColor);

        // Create a mask based on a range around the mean color.

        cv::Scalar halfRange = MASK_STD_DEVS_FROM_MEAN * stdDevColor;

        cv::Scalar lowerBound = meanColor - halfRange;

        cv::Scalar upperBound = meanColor + halfRange;

        cv::inRange(image, lowerBound, upperBound, mask);

        // Erode the mask to merge neighboring blobs.

        int kernelWidth = (int)(MIN(image.cols, image.rows) * MASK_EROSION_KERNEL_RELATIVE_SIZE_IN_IMAGE);

        if (kernelWidth > 0) {

            cv::Size kernelSize(kernelWidth, kernelWidth);

            cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, kernelSize);

            cv::erode(mask, mask, kernel, cv::Point(-1, -1), MASK_NUM_EROSION_ITERATIONS);

        }

    }

    相关文章

      网友评论

          本文标题:iOS下使用OpenCV进行图像识别(不使用Haar和LBP,不

          本文链接:https://www.haomeiwen.com/subject/mkgxvftx.html