Deep learning, hydroponics, and medical marijuana

In today’s blog post we will investigate a practical use case of applying deep learning to hydroponics, a type of method used to grow plants without soil using mineral-rich nutrient solutions in a water solvent.

Specifically, you will learn how to train a Convolutional Neural Network (CNN) using Keras to automatically classify root health without having to physically touch the plants.

The actual experiment design of this tutorial is motivated by Darrah et al. in their 2017 paper, Real- time Root Monitoring of Hydroponic Crop Plants: Proof of Concept for a New Image Analysis System.

Such a system can improve the yields of existing hydroponic farms making farms more efficient and sustainable to run. Of course, the successful application of hydroponics has massive implications for the medical marijuana industry.

While potentially controversial, and knowing full well that I’m going to get a few angry/upset emails about this blog post, I decided to post today’s tutorial anyway.

It’s important, useful, and highly educational for us as students, researchers, and engineers to see practical examples of how deep learning can and is being applied in the real-world.

Furthermore, today’s tutorial is not meant to be a discussion on the legality, morality, or usage of marijuana — this is not a platform to share “Legalize It” or NORML campaigns, anti-drug campaigns, or simply have a discussion on the recreational use of marijuana. There are more than enough websites on the internet to do that already, and if you feel the need to have such a discussion please do, just understand that PyImageSearch is not that platform.

I’d also urge you to keep in mind that we’re all researchers, students, and developers here, and most importantly, we’re all here to learn from practical, real-world examples. Be civil, regardless of whether you agree or disagree with some of the downstream implications of hydroponics.

With all that said, to learn more about how deep learning is being applied to hydroponics (and yes, medical marijuana), just keep reading!

Looking for the source code to this post?
Jump right to the downloads section.

Deep learning, hydroponics, and medical marijuana

In the first half of today’s blog post, we’ll briefly discuss the concept of hydroponic farms, the relation they have to marijuana, and how deep learning intersects them both.

From there we’ll implement a Convolutional Neural Network with Keras to automatically classify root health of plants grown in a hydroponic system without having to physically touch or interfere with the plant.

Finally, we’ll review the results of our experiment.

What is hydroponics?

Figure 1: Hydroponic farming is useful to grow and yield more plants within confined spaces. Read the rest of this case study to find out how Keras + deep learning can be used to spot hydroponic root system problem areas.

Hydroponics is a massive industry with an estimated market value of $21,203.5 million USD (yes, million) in 2016. The market is expected to grow at a 6.5% Compound Annual Growth Rate (CAGR) year over year from 2018 to 2023. Europe and Asia are expected to grow at similar rates as well (source for all statistics).

Hydroponics itself is a subset of hydroculture, the process of growing plants without utilizing soil and instead using mineral-rich solutions in a water solvent.

Using hydroponic methods, plants can grow with only their roots touching the mineral solution.

If you automatically correlate the term “hydroponics” with “marijuana”, keep in mind that hydroponic farming has been endorsed and used by major governments and organizations, including the United States, NASA, Europe and even the fabled Hanging Gardens of Babylon.

A great example is the International Space Station (ISS) — we’ve had hydroponic experiments, including growing vegetables, going on at the ISS for years.

Hydroponics is a science that has existed since the Babylonians and Aztecs, and continues to be used in modern times — so before you turn your nose up, keep in mind that this is actual science, and a science far older than computer vision and deep learning.

So, why bother with hydroponic farming at all?

Nutrient soil continues to come at a premium, especially due to irresponsible or over-farming of land, disease, war, deforestation, and an ever-changing environment just to name a few.

Hydroponic farms allow us to grow our fruits and veggies in smaller areas where traditional soil farms may be impossible.

And if you want to consider an even bigger picture, hydroponics will undoubtedly be utilized if we were to ever colonize Mars.

What does hydroponics have to do with medical marijuana?

Figure 2: Despite the controversy over the legalization of marijuana in some states in the US, marijuana is often grown via hydroponic means and makes for a great use case of plant root health analysis. Deep learning, by means of the Keras library, is used in this blog post to classify “hairy” (good) vs “non-hairy” (poor) root systems in hydroponics.

If you read the previous section on what hydroponics is and why we use the method, it should come as no surprise that hydroponics is widely used in the marijuana industry, even before legalization legislation (in some states) in the United States.

I’m not going to provide an exhaustive review of hydroponics and medical marijuana (for that, you can refer to this article), but the gist is that:

  1. Prior to the legalization of marijuana (in some states of the United States), growers would want to keep their plants secret and safe — growing indoors hydroponically helped with this problem.
  2. Medical marijuana rules are new in the United States and in some cases, the only allowed method to grow is hydroponically.
  3. Growing hydroponically can help conserve our valuable soil which can take decades or more to naturally replenish itself.

According to reports from the Brightfield Group, the cannabis market was valued at $7.7 billion back in 2017 with a Compound Annual Growth Rate as high as 60% percent as other countries and states legalize — this adds up to a market valuation of $31.4 billion come 2021 (source).

There is a lot of money in hydroponics and marijuana, and in a high-risk, high-reward industry that is inherently dependent on (1) legislation and (2) technology, deep learning has found yet another application.

How do deep learning, computer vision, and hydroponics intersect?

Figure 3: PyImageSearch reader, Timothy Darrah’s research lab for analyzing plant root health in a hydroponics growing configuration is pictured with his permission. His project inspired this deep learning blog post.

Back in 2017, PyImageSearch reader Timothy Darrah, an undergraduate at Tennessee State University, reached out to me with an interesting problem — he needed to devise an algorithm to automatically classify plant roots without being able to touch or interfere with the plants in anyway.

In particular, Darrah was working with switchgrass plants, a dominant species of North American prairie grass.

Note: Darrah et al.’s work was published in a paper entitled Real- time Root Monitoring of Hydroponic Crop Plants: Proof of Concept for a New Image Analysis System. Darrah has graciously allowed me to host his paper for your viewing.

The overall goal of the project was to develop an automated root growth analysis system capable of accurately measuring the roots followed by detecting any growth problems:

Figure 4: An automated root growth analysis system concept. We’re demonstrating the concept of deep learning as a tool to help classify the roots in a hydroponic system.

In particular, roots needed to be classified into two groups:

  1. “Hairy” roots
  2. “Non-hairy” roots

The “hairier” a root is, the better the root can suck up nutrients.

The “less hairy” the root is, the fewer nutrients it can intake, potentially leading to the plant starving and dying.

For this project, Timothy, along with Mahesh Rangu (a Ph.D. student) and their advisors, Dr. Erdem Erdemir and Dr. Suping Zhou, developed a system to automatically capture root images without having to disturb the plant itself.

Example images of their experimental setup can be seen in Figure 3 at the top of this section.

From there, they needed to apply computer vision to classify the root into one of the two categories (and eventually multiple categories for detecting other root afflictions).

The only question was how to solve the image classification problem?

Note: Timothy and the rest of the team solved their initial problem after Timothy emailed me in April 2017 asking for an algorithm to try. I suggested Local Binary Patterns which worked for them; however, for the sake of this tutorial, we’ll explore how deep learning can be utilized as well.

Our image dataset

Figure 5: Our deep learning dataset for hydroponics root analysis.

Our dataset of 1,524 root images includes:

  • Hairy: 748 images (left)
  • Non-hairy: 776 images (right)

A subset of the example images for each class can be seen in Figure 4 above.

The original images were captured at a higher resolution of 1920×1080 pixels; however, for the sake for this blog post, I’ve resized them to 256×256 pixels as a matter of convenience (and to save space/bandwidth).

The resizing was performed by:

  1. Resizing the height to 256 pixels
  2. And then taking the center 256-pixel crop

Since the center of the image always contained the mass of root hairs (or lack thereof), this resizing and cropping method worked quite well.

Darrah et al. have graciously allowed us to use these images for our own education as well (but you cannot use them for commercial purposes).

In the remainder of this tutorial, you will learn how to train a deep learning network to automatically classify each of these root species classes.

Project structure

To review the project structure directly in your terminal, first, grab the “Downloads” for this post and unzip the archive.

Then navigate into the project directory and use the tree  command to examine the contents:

Our dataset/  directory consists of hairy_root/  and non_hairy_root/  images.

The pyimagesearch/  directory is a Python module containing . The SimpleNet  architecture is a Keras deep learning architecture I designed for root health classification. We’ll be reviewing this architecture today.

We’ll then train our network with , producing plot.png , our training plot. We’ll walk through the training script line by line so you have an understanding of how it works.

Let’s begin!

Utilizing deep learning to classify root health

Now that we have an understanding of both (1) hydroponics and (2) the dataset we are working with, we can get started.

Installing necessary software

For today’s case study, you’ll need the following software installed on your computer:

  • OpenCV: Any version will work for today’s example as we are just taking advantage of its basic functionality. Visit my OpenCV Tutorials, Resources, and Guides and select the install tutorial appropriate for your system.
  • Keras and TensorFlow: See Installing Keras with TensorFlow backend to get started. Take note of the name of the Python virtual environment you installed OpenCV into — you’ll want to use the same environment to install Keras and TF in.
  • scikit-learn: Easily install into your virtual environment with pip: pip install scikit-learn .
  • imutils: My package of convenience functions for image processing can be installed via  pip install imutils .
  • matplotlib: A plotting tool for Python — pip install matplotlib .

Implementing our Convolutional Neural Network

Figure 6: Our deep learning Convolutional Neural Network (CNN) is based on the concepts of AlexNet and OverFeat. Keras will be utilized to build the network and train the model. We will apply this CNN to hydroponics root analysis where marijuana growers might take notice as hydroponics accounts for a segment of their agriculture industry.

The network we’ll be implementing today is loosely based on concepts introduced in AlexNet and OverFeat.

Our network will start off with convolutional filters with a larger filter size used to quickly reduce the spatial dimensions of the volume. From there we’ll apply two CONV layers used to learn 3×3 filters. Click here to see the full network architecture diagram.

Open up the  file and insert the following code:

We begin our script by importing necessary layer types from keras . Scroll down to see each in use.

We also import the keras backend . The backend will allow us to dynamically handle different input shapes in the next block where we define the SimpleNet  class and build  method:

The SimpleNet  class definition begins on Line 11.

Our only method, build , is defined on Line 13.

The first step in the function is to initialize a Sequential  model (Line 16).

Then we specify our inputShape  where input images are assumed to be 64×64 pixels in size (Line 17).

Most people will be using TensorFlow as the backend which assumes  "channels_last" last ordering. In case you are using Theano or another "channels_first"  backend, then the inputShape  is modified on Lines 20 and 21.

Let’s begin adding layers to our network:

The first CONV => RELU => POOL  block of layers (Lines 24-28) uses a larger filter size to (1) help detect larger groups of hairs (or lack thereof), followed by (2) quickly reducing the spatial dimensions of the volume.

We learn more filters per CONV layer the deeper in the network we go (Lines 31-42).

Standard Rectified Linear Unit (RELU) activation is utilized throughout. Alternatives and tradeoffs are discussed in my deep learning book.

POOL layers have a primary function of progressively reducing the spatial size (i.e. width and height) of the input volume to a layer. You’ll commonly see POOL layers between consecutive CONV layers in a CNN such as this example.

In each of the blocks above, we dropout 25% of the nodes (disconnect random neurons) in an effort to introduce regularization and help the network generalize better. This method is proven to reduce overfitting, increase accuracy, and allow our network to generalize better for unfamiliar images.

Our last FC => RELU  block ends with a softmax classifier:

Fully connected layers ( Dense ) are common towards the end of CNNs. This time we apply 50% dropout.

Our softmax classifier is applied to our last fully connected layer which has 2 outputs corresponding to our two classes : (1) non_hairy_root , and (2) hairy_root .

Finally, we return the constructed model.

Implementing the driver script

Now that we’ve implemented SimpleNet , let’s create the driver script responsible for training our network.

Open up  and insert the following code:

Our driver script has a number of important imports. Let’s review them:

  • matplotlib : The de facto plotting package for Python. We’ll be plotting our training accuracy/loss data over time.
  • SimpleNet : We defined this CNN architecture in the previous section.
  • LabelEncoder : The scikit-learn package has a handy label encoder. We’ll perform “one-hot” encoding — more on that later.
  • train_test_split : We’re going to segment our training data into a certain percentage of images for training and the remaining images for testing. Splitting data is common in machine learning and you’ll find a similar function no matter what tool you are using.
  • classification_report : Allows us to conveniently print statistics in a readable format in our terminal.
  • Adam : A learning optimizer that we’ll be using. Another option would have been SGD.
  • l2 : Incorporated into the loss function, the l2 regularizer allows us to penalize layer parameters or layer activity during optimization. This will prevent overfitting and allow our network to generalize.
  • build_montages : We’ll view the results of our hard work in a montage of images within one frame. This comes from my imutils package.
  • paths : Also from imutils, this function will extract all image paths (recursively) from an input directory.
  • argparse : For parsing command line arguments — we’ll review this next.
  • cv2 : Don’t forget about OpenCV! We’ll use OpenCV for preprocessing as well as visualization/display.
  • os : I’m not a Windows guy, nor do I officially support Windows here on PyImageSearch, but we’ll use os.path.sep  which will accommodate Windows and Linux/Mac path separators.

That was a mouthful. The more you work in the field of CV and DL, the more familiar you’ll become with these and other packages and modules.

Let’s take advantage of one of them. We’ll use argparse  to parse our command line arguments:

Readers of my blog tend to be familiar with these lines of code, but I always explain them for newcomers. The argparse  tool will parse a command string entered in your terminal with command line arguments. Be sure to read my post on Python, argparse, and command line arguments if it is your first time here or if you’ve never used command line arguments before.

We have three command line arguments for our driver script:

  • --dataset : This is the path to our dataset of images. This argument is required as we need data for training.
  • --epochs : You can experiment with training for different numbers of iterations (epochs). I found 100  to be adequate, so it is the default.
  • --plot : If you’d like to specify a path + filename for your plot, you can do so with this argument. By default, your plot will be named "plot.png"  and saved in the current working directory. Each time you run an experiment with a goal of better performance, you should make note of DL parameters and also name your plot so you’ll remember which experiment it corresponds to.

Now that we’ve parsed our command line arguments, let’s load + preprocess our image data and parse labels:

On Line 34 we create a list of all imagePaths  in our dataset. We then go ahead and initialize a place to hold our data  in memory as well as our corresponding  labels  (Lines 35 and 36).

Given our imagePaths , we proceed to loop over them on Line 39.

The first step in the loop is to extract our class label on Line 41. Let’s see how this works in a Python Shell:

Notice how by using  imagePath.split  and providing the split character (the OS path separator — “/” on Unix and “\” on Windows), the function produces a list of folder/file names (strings) which walk down the directory tree (Lines 8 and 9). We grab the second-to-last index, the class label, which in this case is 'hairy_root'  (Lines 10 and 11).

Then we proceed to load the image  and preprocess it (Lines 45-47). Grayscale (single channel) is all we need to identify hairy or non-hairy roots. Our network requires 64×64 pixel images by design.

Finally, we add the image  to data  and the label  to labels  (Lines 50 and 51).

Next, we’ll reshape our data and encode labels:

Data is reshaped on Lines 55-59. During the process, we convert from a list to a NumPy array of floats that are scaled to [0, 1]. We also add the channel dimension even though we have only one grayscale channel. This extra dimension is expected by our CNN.

We then encode our labels on Lines 62-69. We use “one-hot encoding” which implies that we have a vector where only one of the elements (classes) is “hot” at any given time. Review my recent Keras tutorial for an example applied to a dataset of 3 classes to grasp the concept.

Now comes the splitting of the data. I’ve reserved 60% of our data for training and 40% for testing (Lines 73 and 74).

Let’s compile our model:

We initialize the Adam  optimizer with a learning rate of 1e-4  and learning rate decay (Line 78).

Note: The default learning rate for Adam is 1e-3 , but I found through experimentation that using 1e-3  was too high — the network was unable to gain any “traction” and unable to learn. Using 1e-4  as the initial learning rate allowed the network to start learning. This goes to show you how important it is to understand deep learning parameters and fundamentals. Grab a copy of my book, Deep Learning for Computer Vision with Python, to discover my best practices, tips, and suggestions when tuning these parameters.

I also included a small amount of regularization to help prevent overfitting and ensure the network generalizes. This regularization is shown on Lines 79 and 80 where we build  our model while specifying our dimensions, encoded labels, as well as the regularization strength.

We compile  our model on Lines 81 and 82. Since our network has only two classes, we use "binary_crossentropy" . If you have > 2 classes, you would want to use "categorical_crossentropy" .

Training is kicked off next, followed by evaluation:

Training, also known as “fitting a model” is kicked off on Lines 87 and 88. I’ve set a batch size of 32 .

We then evaluate the network and print a classification_report  in the terminal (Lines 92-94).

Next, we use matplotlib to generate a training plot:

The above is a good recipe to refer to for producing a training plot when working with Keras and deep learning. The code plots loss and accuracy on the same plot (y-axis) throughout the training period (x-axis).

We call savefig  to export the plot image to disk (Line 108).

Finally, let’s visualize the output:

Whenever you are testing a machine learning or deep learning model, you shouldn’t only rely on statistics as proof that the model is working. You should also visualize your results on test images. Sometimes I make a separate script which loads an arbitrary image and classifies + displays it. Given that these images are all similar, I opted to make a montage of images so we can visually check at a glance if our model is performing well.

The steps to do this include:

  1. Randomly select some testing image indexes to visualize (Lines 112 and 113). Also initialize a list to hold the images  (Line 114).
  2. Loop over the random image idxs  beginning on Line 117:
    1. Load and classify the image (Lines 119-122). We take the index of the highest prediction and feed the index to our label encoder to generate a label .
    2. Rescale/resize the image for visualization (Lines 126-128).
    3. Draw the label  text on the output image (Lines 132-134). The hairy roots (good) will have green font and non-hairy roots (bad) will be red.
    4. Add the output  image to our images list so that we can later build a montage (Line 135).
  3. Build a montage of the results (Line 138). Learn to build Montages with OpenCV.

Finally, we display the results until a key is pressed on the final two lines.

Root health classification results

To see how our root health deep neural network performed, be sure to use the “Downloads” section of this blog post to download the source code and dataset.

From there, open up a terminal, navigate to where you downloaded + extracted the code, and execute the following command:

Figure 7: Our deep learning training plot contains accuracy and loss curves for our hydroponics plant root health case study. The CNN was trained with Keras and the plot was generated with Matplotlib.

As we can see, our network obtained 99% classification accuracy, and as our plot demonstrates, there is no overfitting.

And furthermore, we can examine the montage of our results which again show that our network is accurately classifying each of the root types:

Figure 8: A montage of our hydroponic root classification system results. Keras + deep learning was utilized to build a “hairy_root” vs “non_hairy_root” classifier. Training images were provided by Darrah et al.’s research.

Using techniques such as this one, deep learning researchers, practitioners, and engineers can help solve real-world problems.


In today’s blog post we explored a real-world application of deep learning: automatically classifying plant root health in hydroponic farms, and in particular, how such a system could be leveraged in the massively growing (no pun intended) medical marijuana industry.

In order to classify root health, we trained a Convolutional Neural Network with Keras and Python to label roots as “hairy” or “non-hairy”.

The more hairs a root has, the more easily it is able to intake nutrients. The fewer hairs a root has, the more it will struggle to suck up nutrients, potentially leading to the plant dying and the loss of the crop.

Using the method detailed in today’s post we were able to classify root health with over 99% accuracy.

For more information on how hydroponics and computer vision intersect, please refer to Darrah et al.’s 2017 publication.

I hope you enjoyed today’s blog post on applying deep learning to a real-world application.

To download the source code to this blog post (and signup for the PyImageSearch newsletter), just enter your email address in the form below!


If you would like to download the code and images used in this post, please enter your email address in the form below. Not only will you get a .zip of the code, I’ll also send you a FREE 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning. Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL! Sound good? If so, enter your email address and I’ll send you the code immediately!

, , , , ,

39 Responses to Deep learning, hydroponics, and medical marijuana

  1. Tim October 15, 2018 at 11:23 am #

    This is awesome! Thanks for sharing!

    • Adrian Rosebrock October 15, 2018 at 11:27 am #

      Thank you for your valuable research contributions, Tim!

  2. Roger October 15, 2018 at 11:36 am #

    Great post!
    Just one question: why is infrared camera used?


  3. Adarshreddy adelli October 15, 2018 at 11:55 am #

    You have done a great job Tim

  4. vijay singh October 15, 2018 at 1:54 pm #

    great post adrian. applications of deep learning these science make computer vision perfect.

    • Adrian Rosebrock October 15, 2018 at 4:28 pm #

      Thanks Vijay!:-)

  5. Cenk October 15, 2018 at 2:30 pm #

    Indeed a great post and thanks for sharing with us!

    By the way, do you know what their accuracy was with LBP (Local Binary Patterns) at their early implementation time?


    • Adrian Rosebrock October 15, 2018 at 4:28 pm #

      It’s honestly been a year since I ran the LBP experiment but I remember it being quite good — somewhere in the range of 95% accuracy.

  6. Walid October 15, 2018 at 2:48 pm #

    Great work as usual

    just curious , why you used 2 classes as output although this is a binary classifier and can work with a single output only and if it is not predicted then it will be the other class directly?

  7. Arsalan October 15, 2018 at 9:56 pm #

    Hi Sir,
    Sorry in advance, because of this stupid question but learning required questions so please don’t mind.
    I have a lot of images and I want to create a data set for training my CNN model. but I don’t know how I can create a dataset with raw images and resize them. can you please guide me?
    I am totally new in the CNN or Neural networks

    • Adrian Rosebrock October 16, 2018 at 8:21 am #

      Hey Arsalan — this guide actually shows you how to create a directory structure to train a CNN. For a more in-depth example, please refer to my Keras tutorial.

  8. Sundaresh Sankaran October 16, 2018 at 12:10 am #

    Hi Adrian

    Thank you for this very helpful post. I just wanted to point out some places where I had to “edit” the code to make it work – I don’t know if it was completely necessary but thought I’ld point it out anyways. These are more around simple python commands so my apologies if these are not important.

    i) My open cv installation was not from source, but from the open-cv-contrib through pip.This meant that in my site-packages I had one more folder called cv2 within my opencv folder. Net result – I had to edit the import code to “import cv2.cv2 as cv2” to get the methods to work.

    ii) list(paths.list_images(args[“dataset”])) – worked only after I changed the dataset argument to “/dataset/” from “dataset” – I feel python needed that slash to understand that it needed to search for images even in the child directories, otherwise it only searched in the main directory (dataset, not dataset/hairy or non-hairy), and found no images)

    iii) I am no biologist, and really sorry if this seems silly, but … on visual inspection, even some of the “non-hairy” images did seem like they had ‘hairs’ or ‘stalks’ or ‘thorns’ … even though the images were labeled, I would really like to understand what exactly were we searching for when we think of ‘hairy’. I understand that is what makes this problem challenging.


    • Adrian Rosebrock October 16, 2018 at 8:18 am #

      1. That sounds like a problem with your OpenCV install. You should diagnose that further as that in no way should be required.

      2. Adding the additional slash shouldn’t be required either.

      3. Just because a stalk has a few hairs doesn’t qualify it as “hairy”. Here a “hairy” stalk should have quite a few hairs. Just one hair alone doesn’t mean that it’s “hairy”.

      • Sundaresh October 16, 2018 at 12:26 pm #

        Thanks again.

  9. Amit Jain October 16, 2018 at 4:42 am #

    Great post as usual.. this is my first end to end guide on using DNN as classifier. I hope to see relevant explanation on neural net architecture and how one is suppose to design it.

  10. Pranav Lal October 16, 2018 at 12:26 pm #

    A fascinating post. Thanks for the explanation of hydroponics. I remember reading about it in middle school chemistry class. You also answered a question I had not asked. I was wondering where you would get the data set for something as specific as this. How did you determine that the data set was sufficient to solve this problem? This is a general question. How do I gauge if the number of images I have for a particular task are enough to accumplish that task?

    • Adrian Rosebrock October 20, 2018 at 8:07 am #

      Hey Pranav, thanks for the comment. As for your questions, I don’t think that’s a question I can answer, only Timothy could weigh in on the dataset gathering process and how he personally knew there was sufficient data for the task, and more importantly, than the model could generalize.

      That said, even without hydroponics domain experience we can still look at this problem and see that we have sufficient data by simply running a few more experiments, namely by (1) using an additional testing split and then (2) applying it to new images that were just captured. If our model performs well we know we have reached sufficient generalization.

  11. Leonmat October 16, 2018 at 9:01 pm #

    How come i trained it with categorical_crossentropy, it is still able to train and predicts well. There must be something i missed, can you explain what just happen?

    • Adrian Rosebrock October 20, 2018 at 8:01 am #

      We trained using binary_crossentropy for this post. Are you saying that you switched to categorical_crossentropy just to see what would happen?

  12. Mekel Mythri October 18, 2018 at 12:03 pm #

    Again a Great Blog.
    Thanks Adrian for sharing your immensive knowledge..
    Keep Rocking…!

    • Adrian Rosebrock October 20, 2018 at 7:40 am #

      Thanks Mekel, I’m glad you liked it! 🙂

  13. Trami October 19, 2018 at 10:58 pm #

    Hi Adrian. I have a question about the
    ‘(trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.40, stratify=labels, random_state=42)’

    i just wonder the function of the ‘ stratify=labels’ , and i could’t find the meaning in sklearn reference.

    • Adrian Rosebrock October 20, 2018 at 7:23 am #

      Stratified sampling attempts to keep the class distribution approximately equal ensuring there are little class imbalances when building your training and testing set.

      • Trami October 21, 2018 at 10:12 am #

        I still have a question about the structure of the CNN.

        This CNN uses dropout behind the convolution layer and pooling layer.
        Is there any advantage in this structure ?

        Secondly, this CNN uses regularization in every convolution layer rather than using in the cost function.
        I also want to know the reason about that.

        Hope you can solve the questions for me. Thank you !!

        • Adrian Rosebrock October 22, 2018 at 8:02 am #

          1. Dropout is another form of regularization. While not required, I often like to include a small amount of Dropout between CONV blocks. It’s worth a try in your own data as well.

          2. See the Keras regularizers documentation.

  14. Kong October 20, 2018 at 1:40 pm #

    Hi Adrian~
    Every time I look at your Post I am studying.
    I want to ask a question.
    In this experiment, you have learned to collect and distinguish between ‘hairy’ and ‘non hairy’ data.
    However, if there is only a sample of ‘hairy’ and there is no sample of ‘non hairy’,
    Is it possible to distinguish between ‘hairy’ and ‘non hairy’ by learning only the photo samples of ‘hairy’?
    By learning only one type of photograph,
    Can you compare how many other pictures are similar to those of other pictures?

    • Adrian Rosebrock October 22, 2018 at 8:11 am #

      No, you need at least two classes of data to perform classification using this tutorial. If you only have one class and are looking to detect if one sample is sufficiently different than the rest you should instead look into “outlier detection”.

      • Kong October 22, 2018 at 11:10 am #

        Thank you for answer. If I refer to any part of your lecture, can I get more information about “outlier detection”?

  15. Amanda Boatswain Jacques October 30, 2018 at 2:33 pm #

    This is totally awesome! Great real-world application of computer vision and deep learning in greenhouses. I’ve shared this with the ag-robotics team at my campus, hopefully they will be inspired by all the great possibilities of CV in agriculture and hydroponics. Thank you Adrian! 🙂

    • Adrian Rosebrock November 2, 2018 at 8:18 am #

      Thanks so much for sharing the post, Amanda! I hope all is well with you 🙂

  16. Wellington Betio November 20, 2018 at 12:14 pm #

    Good afternoon, I work on the development of applications involving computer vision in Brazil.
    Currently I have an application in which I need to classify eucalyptus seedlings, being necessary the detection of branching, pairs of leaves, length, diameter and coloring of the plants. The path would be deep learning? If you are interested in creating a case about this application, please contact me via e-mail, I have a large number of images.

  17. Will Li March 4, 2019 at 5:20 am #

    Hi Adrian,

    This is a great post as the others of yours, thanks!

    May I ask a question.
    What did you do if the camera captured roots of multiple units in one image, do you need to segment them out?
    Or is it required that only one single root can be capture mostly at one time? But how to ensure that, how to design a automatic camera is a follow-up question 🙂


  18. Ashith May 9, 2019 at 3:32 am #

    You mention that the work is based on OverFeat, yet the major concepts in overfeat (Localization and detection) does not seem to be used in any way. Did you maybe only take the classification network architecture?

  19. Srivatsan June 7, 2019 at 10:07 am #

    Hey, Adrian i am working on this project on face detection, but whenever I try to save the video file through the code, the video file gets saved but it’s size is of about a few bytes or 6KB most of the time. I even used your code to do the same, but the results remained the same.
    The video file gets saved successfully whenever i use the normal video stream code without any model’s or CNNs.(Without face/ object detection code)
    I did the same on my cousin’s PC but even he’s getting the same error.
    Where could I be going wrong?

    • Adrian Rosebrock June 12, 2019 at 1:56 pm #

      OpenCV’s video writing functions can be a pain. It’s most likely a codec problem. Try following this tutorial.

Before you leave a comment...

Hey, Adrian here, author of the PyImageSearch blog. I'd love to hear from you, but before you submit a comment, please follow these guidelines:

  1. If you have a question, read the comments first. You should also search this page (i.e., ctrl + f) for keywords related to your question. It's likely that I have already addressed your question in the comments.
  2. If you are copying and pasting code/terminal output, please don't. Reviewing another programmers’ code is a very time consuming and tedious task, and due to the volume of emails and contact requests I receive, I simply cannot do it.
  3. Be respectful of the space. I put a lot of my own personal time into creating these free weekly tutorials. On average, each tutorial takes me 15-20 hours to put together. I love offering these guides to you and I take pride in the content I create. Therefore, I will not approve comments that include large code blocks/terminal output as it destroys the formatting of the page. Kindly be respectful of this space.
  4. Be patient. I receive 200+ comments and emails per day. Due to spam, and my desire to personally answer as many questions as I can, I hand moderate all new comments (typically once per week). I try to answer as many questions as I can, but I'm only one person. Please don't be offended if I cannot get to your question
  5. Do you need priority support? Consider purchasing one of my books and courses. I place customer questions and emails in a separate, special priority queue and answer them first. If you are a customer of mine you will receive a guaranteed response from me. If there's any time left over, I focus on the community at large and attempt to answer as many of those questions as I possibly can.

Thank you for keeping these guidelines in mind before submitting your comment.

Leave a Reply