首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于OpenCV的叶片病害检测与识别

基于OpenCV的叶片病害检测与识别
EN

Stack Overflow用户
提问于 2014-11-28 09:25:54
回答 1查看 5.7K关注 0票数 3

你能帮我做这个吗。

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

在这件事上我要用什么方法?我已经研究过直方图匹配、关键点匹配和描述符匹配,但我不确定哪一个最有效。

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

代码语言:javascript
复制
#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/描述符匹配,那么什么算法是冲浪和FLANN的最佳替代方案,因为我也将在android平台上实现它?我还需要进行阈值处理还是分割?它会不会删除重要的细节,如颜色,形状等?拜托,伙计们,建议一些步骤来做这个。
EN

回答 1

Stack Overflow用户

发布于 2014-11-28 12:53:49

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

培训过程。

  1. 提取图像像素的LBP描述符(也可以计算彩色图像)。
  2. 计算每个训练样本的LBP描述符直方图。
  3. 使用直方图作为输入和标签作为输出来训练分类器。

预测过程:

  1. 提取新图像像素的LBP描述子。
  2. 计算此图像的LBP描述符直方图。
  3. 将历史数据反馈给分类器->,得到结果。

我成功地使用前馈神经网络作为分类器,解决了类似的问题。

你可能会发现这本书很有用: ISBN 978-0-85729-747-1“使用本地二进制模式的计算机视觉”

试试这个(计算LBP描述符,也有计算直方图的功能):

代码语言:javascript
复制
#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;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27185477

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档