使用OpenCV进行叶病检测和识别

时间:2014-11-28 09:25:54

标签: android c++ opencv

你可以帮我解决这个问题。

我的任务是使用OpenCV和c ++创建一个应用程序,它将接收植物叶子的图像输入。该应用将检测可能的疾病症状,例如来自叶子的黑色/灰色/褐色斑点,或枯萎病,病变等。疾病的每种特征(例如斑点的颜色)代表不同的疾病。在检测到可能的症状后,应用程序将其与应用程序数据库中的模板图像集合进行匹配,并输出可能的最佳匹配。

我必须使用哪些方法?我已经研究了直方图匹配和关键点和描述符匹配,但我不确定哪一个最适合。

我找到了使用SURF和FLANN的示例代码,但我不知道这是否足够:

#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/nonfree/features2d.hpp"

using namespace cv;

void readme();

/**
* @function main
* @brief Main function
*/
int main( int argc, char** argv )
{
if( argc != 3 )
{  readme(); return -1; }

Mat img_1 = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );
Mat img_2 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );

if( !img_1.data || !img_2.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }

//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;

SurfFeatureDetector detector( minHessian );

std::vector<KeyPoint> keypoints_1, keypoints_2;

detector.detect( img_1, keypoints_1 );
detector.detect( img_2, keypoints_2 );

//-- Step 2: Calculate descriptors (feature vectors)
SurfDescriptorExtractor extractor;

Mat descriptors_1, descriptors_2;

extractor.compute( img_1, keypoints_1, descriptors_1 );
extractor.compute( img_2, keypoints_2, descriptors_2 );

//-- Step 3: Matching descriptor vectors using FLANN matcher
 FlannBasedMatcher matcher;
 std::vector< DMatch > matches;
 matcher.match( descriptors_1, descriptors_2, matches );

 double max_dist = 0; double min_dist = 100;

 //-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_1.rows; i++ )
{ double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
 }

printf("-- Max dist : %f \n", max_dist );
printf("-- Min dist : %f \n", min_dist );

//-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist,
//-- or a small arbitary value ( 0.02 ) in the event that min_dist is very
//-- small)
//-- PS.- radiusMatch can also be used here.
std::vector< DMatch > good_matches;

for( int i = 0; i < descriptors_1.rows; i++ )
{ if( matches[i].distance <= max(2*min_dist, 0.02) )
{ good_matches.push_back( matches[i]); }
}

//-- Draw only "good" matches
Mat img_matches;
drawMatches( img_1, keypoints_1, img_2, keypoints_2,
           good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
           vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );

//-- Show detected matches
imshow( "Good Matches", img_matches );

for( int i = 0; i < (int)good_matches.size(); i++ )
{ printf( "-- Good Match [%d] Keypoint 1: %d  -- Keypoint 2: %d  \n", i,           good_matches[i].queryIdx, good_matches[i].trainIdx ); }

 waitKey(0);

return 0;
}

  /**
  * @function readme
 */
    void readme()
 { std::cout << " Usage: ./SURF_FlannMatcher <img1> <img2>" << std::endl; }

以下是我的问题:

  1. 我必须使用哪种方法?直方图匹配,关键点/描述符匹配或?

  2. 如果我使用Keypoint / Descriptor匹配,什么算法是SURF和FLANN的最佳替代方法,因为我将在Android平台上实现它?我还需要进行阈值处理或分割吗?它是否会删除重要的细节,如颜色,形状等?请伙计们,建议采取一些措施。

1 个答案:

答案 0 :(得分:1)

我认为这种方式应该会给你带来好结果:

培训过程。

  1. 提取图像的异常像素的LBP描述符(可以计算 对于彩色图像也是如此。
  2. 计算每个训练样本的LBP描述符的直方图。
  3. 使用直方图作为输入并使用标签作为输出来训练分类器。
  4. 预测过程:

    1. 为新图像的异常像素提取LBP描述符。
    2. 计算此图像的LBP描述符的直方图。
    3. 将历史记录添加到分类器 - &gt;得到结果。
    4. 我成功地将前馈神经网络用作分类器,以解决类似的问题。

      您可能会发现本书很有用:ISBN 978-0-85729-747-1&#34;使用本地二进制模式的计算机视觉&#34;

      尝试这个(计算LBP描述符,还有计算直方图的函数):

      #include <iostream>
      #include <opencv2/opencv.hpp>
      #include <opencv2/imgproc/imgproc.hpp>
      #include <opencv2/highgui/highgui.hpp>
      #include <opencv2/features2d/features2d.hpp>
      #include "opencv2/nonfree/nonfree.hpp"
      #include <limits>
      using namespace cv;
      
      class myLBP
      {
      public:
          uchar lut[256];
          uchar null;
          int radius;
          int maxTransitions;
          bool rotationInvariant;
      
          myLBP(int _radius=1,int _maxTransitions=8,bool _rotationInvariant=false)
          {
              radius=_radius;
              maxTransitions=_maxTransitions;
              rotationInvariant=_rotationInvariant;
      
              bool set[256];
              uchar uid = 0;
              for (int i=0; i<256; i++)
              {
                  if (numTransitions(i) <= maxTransitions)
                  {
                      int id;
                      if (rotationInvariant)
                      {
                          int rie = rotationInvariantEquivalent(i);
                          if (i == rie)
                          {
                              id = uid++;
                          }
                          else
                          {
                              id = lut[rie];
                          }
                      }
                      else
                      {
                          id = uid++;
                      }
                      lut[i] = id;
                      set[i] = true;
                  }
                  else
                  {
                      set[i] = false;
                  }
              }
              null = uid;
              for (int i=0; i<256; i++)
                  if (!set[i])
                  {
                      lut[i] = null;    // Set to null id
                  }
          }
      
      
          /* Returns the number of 0->1 or 1->0 transitions in i */
          static int numTransitions(int i)
          {
              int transitions = 0;
              int curParity = i%2;
              for (int j=1; j<=8; j++)
              {
                  int parity = (i>>(j%8)) % 2;
                  if (parity != curParity)
                  {
                      transitions++;
                  }
                  curParity = parity;
              }
              return transitions;
          }
      
          static int rotationInvariantEquivalent(int i)
          {
              int min = std::numeric_limits<int>::max();
              for (int j=0; j<8; j++)
              {
                  bool parity = i % 2;
                  i = i >> 1;
                  if (parity)
                  {
                      i+=128;
                  }
                  min = std::min(min, i);
              }
              return min;
          }
      
          void process(const Mat &src, Mat &dst) const
          {
              Mat m;
              src.convertTo(m, CV_32F);
              assert(m.isContinuous() && (m.channels() == 1));
              Mat n(m.rows, m.cols, CV_8UC1);
              n = null; // Initialize to NULL LBP pattern
              const float *p = (const float*)m.ptr();
              for (int r=radius; r<m.rows-radius; r++)
              {
                  for (int c=radius; c<m.cols-radius; c++)
                  {
                      const float cval  =     (p[(r+0*radius)*m.cols+c+0*radius]);
                      n.at<uchar>(r, c) = lut[(p[(r-1*radius)*m.cols+c-1*radius] >= cval ? 128 : 0) |
                          (p[(r-1*radius)*m.cols+c+0*radius] >= cval ? 64  : 0) |
                          (p[(r-1*radius)*m.cols+c+1*radius] >= cval ? 32  : 0) |
                          (p[(r+0*radius)*m.cols+c+1*radius] >= cval ? 16  : 0) |
                          (p[(r+1*radius)*m.cols+c+1*radius] >= cval ? 8   : 0) |
                          (p[(r+1*radius)*m.cols+c+0*radius] >= cval ? 4   : 0) |
                          (p[(r+1*radius)*m.cols+c-1*radius] >= cval ? 2   : 0) |
                          (p[(r+0*radius)*m.cols+c-1*radius] >= cval ? 1   : 0)];
                  }
              }
              dst=n.clone();
          }
      
          /* Returns the number of 1 bits in i */
          static int bitCount(int i)
          {
              int count = 0;
              for (int j=0; j<8; j++)
              {
                  count += (i>>j)%2;
              }
              return count;
          } 
      
          void draw(const Mat &src, Mat &dst) const
          {
              static Mat hueLUT, saturationLUT, valueLUT;
              if (!hueLUT.data)
              {
                  const int NUM_COLORS = 10;
                  hueLUT.create(1, 256, CV_8UC1);
                  hueLUT.setTo(0);
                  uchar uid = 0;
                  for (int i=0; i<256; i++)
                  {
                      const int transitions = numTransitions(i);
                      int u2;
                      if   (transitions <= 2)
                      {
                          u2 = uid++;
                      }
                      else
                      {
                          u2 = 58;
                      }
                      // Assign hue based on bit count
                      int color = bitCount(i);
                      if (transitions > 2)
                      {
                          color = NUM_COLORS-1;
                      }
                      hueLUT.at<uchar>(0, u2) = 255.0*(float)color/(float)NUM_COLORS;
                  }
                  saturationLUT.create(1, 256, CV_8UC1);
                  saturationLUT.setTo(255);
                  valueLUT.create(1, 256, CV_8UC1);
                  valueLUT.setTo(255.0*(3.0/4.0));
              }
              if (src.type() != CV_8UC1)
              {
                  std::cout << "Expected 8UC1 source type.";
      
              }
              Mat hue, saturation, value;
              LUT(src, hueLUT, hue);
              LUT(src, saturationLUT, saturation);
              LUT(src, valueLUT, value);
              std::vector<Mat> mv;
              mv.push_back(hue);
              mv.push_back(saturation);
              mv.push_back(value);
              Mat coloredU2;
              merge(mv, coloredU2);
              cvtColor(coloredU2, dst, cv::COLOR_HSV2BGR);
          } 
      };
      
      
      void Hist(const Mat &src, Mat &dst,float max=256, float min=0,int dims=-1)
      {
          std::vector<Mat> mv;
          split(src, mv);
          Mat m(mv.size(), dims, CV_32FC1);
          for (size_t i=0; i<mv.size(); i++)
          {
              int channels[] = {0};
              int histSize[] = {dims};
              float range[] = {min, max};
              const float* ranges[] = {range};
              Mat hist, chan = mv[i];
              // calcHist requires F or U, might as well convert just in case
              if (mv[i].depth() != CV_8U && mv[i].depth() != CV_32F)
              {
                  mv[i].convertTo(chan, CV_32F);
              }
              calcHist(&chan, 1, channels, Mat(), hist, 1, histSize, ranges);
              memcpy(m.ptr(i), hist.ptr(), dims * sizeof(float));
          }
          dst=m.clone();
      }
      
      
      
      int main(int argc, char* argv[])
      {
          cv::initModule_nonfree();
          cv::namedWindow("result");
          cv::Mat bgr_img = cv::imread("D:\\ImagesForTest\\lena.jpg");
          if (bgr_img.empty()) 
          {
              exit(EXIT_FAILURE);
          }
          cv::Mat gray_img;
          cv::cvtColor(bgr_img, gray_img, cv::COLOR_BGR2GRAY);
          cv::normalize(gray_img, gray_img, 0, 255, cv::NORM_MINMAX);
      
          myLBP lbp(1,2);
          Mat lbp_img;
      
          lbp.process(gray_img,lbp_img);
          lbp.draw(lbp_img,bgr_img);
      
          //for(int i=0;i<lbp_img.rows;++i)
      
          imshow("result",bgr_img);
          cv::waitKey();
          return 0;
      }