jeffbass / yin-yang-ranch

Distributed Computer Vision Software & Raspberry Pis to help manage a farm
MIT License
92 stars 21 forks source link

YAML settings to detect birds in flight #5

Closed sbkirby closed 4 years ago

sbkirby commented 4 years ago

Jeff, I'm attempting to use imagenode with a DIY RPi Sky Camera to detect birds flying/migrating over my house, but I'm not having any success. I've used the Test #3 in imagenode/blob/master/docs/testing.rst in an attempt to tune my YAML file, but I'm not having any success. I've adjusted the delta_threshold, min_area, blur_kernel_size, min_motion_frames, and can't seem to get it to trigger satisfactorily. Am I asking to much of the software to detect such small objects? I've adjusted the min_area to as low as 0.1, and delta_threshold to 1. I'm using a resolution of 1920,1456, and a framerate of 30 with a RPi HQ Camera Module. Are there any adjustments you would recommend to achieve my goal. The raptor migration season is just beginning here in Texas, and we have numerous Mississippi Kites flying over the house in the morning.

jeffbass commented 4 years ago

Hi Stephen,

I'm not sure if the software can work at those values, especially the resolution. The largest resolution I use is 640x480 and I can get about 16 FPS. I just tried a test with a resolution of 1920x1456, I could only get a max of 2 FPS (both tests are sending jpgs). This is when testing with send_frames: continuous. It might be slightly faster when using send_frames: detected event. But I’m not sure that the imagenode —> imageZMQ —> imagehubpipeline is appropriate for a resolution higher than 640x480. I do my testing with imagenoge/imagenode.pysending and imagenode/tests/receive_test.py receiving.

As for the other settings, I have never used a min_area less than 2. I have used delta_threshold of 3 most often. Although it is included in test3.yaml I don’t use the resize_width option at all in deployed imagenodes; it slows down the FPS noticeably.

I never deploy an imagenode PiCamera motion detector without first bench testing it inside with send_test_images: True. Some of my test images are shown in the imagenode README. I find that I need to see the impact of min_area, delta_threshhold, blur_kernel_size visually, in order to pick values for my ROI. My tests often use the “ballpoint pen swinging on a string” test setup shown in the README, but I have also tossed a ping pong ball through the PiCamera field of view. Again, I have never tested on resolutions larger than 640x480. The motion detector algorithm may need to be changed to work at resolutions larger than 640x480.

Thanks for your question. It makes me realize I need to document clearly that I have never tested any of this software at resolutions higher than 640x480. If I were to do such testing, I would probably modify imagenode to capture frames rapidly to a large memory buffer and then use a separate process to empty that memory buffer by sending images via imageZMQ. Python 3.8 has made such inter-process large memory buffers possible. It would allow high speed image capture and detection, but only until the buffer filled up. In my “bursts of motion with long periods of no motion” use case, that might work OK. I don’t know how well it would work with birds.

For reference, here is my imagenode.yamlfor my barn “coyote” cam:

# Settings file for imagenode.py barn camera
---
node:
  name: Barn
  print_settings: False
  patience: 30
  send_threading: False
  stall_watcher: True
  heartbeat: 2
hub_address:
  H1: tcp://192.168.86.71:5555
cameras:
  P1:
    resolution: (640, 480)
    framerate: 16 
    vflip: True   # change to True or False to suit your RPi PiCamera
    exposure_mode: night
    detectors:
      motion:
        ROI: (2,2),(98,98)
        draw_roi: ((255,0,0),1)
        send_frames:  detected event # continuous or none or detected event
        send_count: 4
        delta_threshold: 3
        min_motion_frames: 2
        min_still_frames: 5
        min_area: 2  # minimum area of motion as percent of ROI
        blur_kernel_size: 15  # Guassian Blur kernel size
        send_test_images: False
sensors:
  T1:
    name: Temp
    type: DS18B20
    gpio: 4
    read_interval_minutes: 15  # read sensor every X minutes 
    min_difference: 1  # send if this much change in degrees

The ROI is effectively the entire field of view. It captures coyotes, bobcats, raccoons and rabbits well. It captures birds in flight when they are close. Crows at 20 feet; hummingbirds at less than 10 feet. I don’t know if this software pipeline would work well to capture birds at any further than that, since they wouldn’t be very big in a 640x480 frame.

Hope this answer helps clarify the settings I use. If you do get a higher resolution than 640x480 to work, please let me know the settings. Or any improvements you make to the motion detector. Thanks, Jeff

sbkirby commented 4 years ago

Jeff, Thanks for the feedback. After tweaking the min_area, blur_kernel_size and min_motion_frames, I was able to get it to work. I've attached a screen shot of the a raptor flying over the house, and the shot includes the terminal with the settings displayed. Notice the min_area = 0.006% (or 44 pixels). This seems to be working OK...I'll keep you informed. Screenshot 2020-08-04 11 51 04

By the way, my primary server is a Linux system, but my main programming and testing platform has been Windows 10. A couple of your programs will not run on Windows. They include imagenode/tests/receive_test.py and imagehub/tools/utils.py, which have the same line of code in each. Unfortunately, I can't find a fix for the error because there doesn't appear to be a simple equivalent example of Windows code.

     # code in both routines
     signal.signal(signal.SIGALRM, self.raise_timeout)
     signal.alarm(self.seconds)
# code in utils.py
from sys import platform
...
def __enter__(self):
        if platform != "win32":
            signal.signal(signal.SIGALRM, self.raise_timeout)
            signal.alarm(self.seconds)
        else:
            pass

    def __exit__(self, *args):
        if platform != "win32":
            signal.alarm(0)    # disable alarm
        else:
            pass

The above will run without an error, but the timing test (FPS) in receive_test.py doesn't work in Windows.

Thanks, Stephen

sbkirby commented 4 years ago

Jeff, If you like, I can create a Pull Request for the issue mentioned above.

Stephen

jeffbass commented 4 years ago

Hi Stephen,

Wow. Well done on the birds image capture. I had no idea that the motion detector could be tuned to such a small ROI percentage. Thanks for sharing.

Your settings are very different from anything I have used (obviously, since I've never used such high resolution images ;-). Would be willing to contribute your yaml file to the yaml folderin imagenode? You could include a couple of comments lines at the top of the yaml file explaining it and its value in detecting the motion of birds. Include a "Contributed by" comment line also. Name it bird_cam_rpi.yaml. Then do a pull request to so I could merge it into the imagenode repository.

I did not intend the use of signal.SIGALRM to create problems for Windows users. I just automatically use common unix OS features without thinking about it. SIGALRM is definitely unix / Linux only; the Python documentation for the signal module points that out. For Windows, instead of using receive_test.py, use the program imagezmq/tests/timing_receive_jpg_buf.py. It is in the imageZMQ repository and does not use any unix system calls. But it will have to be stopped with Ctrl-C, since it has no unix timer running. I will create a Windows friendly version of receive_test.py and put it in the imagenode/tests directory, but I won't get to that right away. The imagezmq/tests/timing_receive_jpg_buf.py program should work for you until then.

Instead of doing a pull request, would you be willing to copy / paste your code and problem description and solution as an imagenode issue? That way any other imagenode Windows users will see it. I'll come up with a better way to implement the Patience class that does not involve signal.SIGALRM. I am glad your workaround code is working for you, but I'd rather replace the Patience class with something that is more Windows friendly.

Thanks, Jeff

sbkirby commented 4 years ago

Jeff, Thanks for your help on this matter. Stephen