Controlling Stepper motors and Camera simultaneously - python

what is the best way to control a stepper motor and camera simultaneously?
Suppose the camera is placed on a linear stage (stepper motor) and I want to move the stage in 1 mm steps and capture a frame at the end of each step. Both devices (Camera and the stage) are connected to my computer (Ubuntu 18.04.3 LTS) via 2 different USB 2.0 ports.
My script for the camera looks something like:
def camera():
...
...
...
while(True):
cv2.imshow('live', frame)
ueye.is_ExitCamera(hCam2)
cv2.destroyAllWindows()
if __name__ == "__main__":
camera()
and outputs live broadcast from the camera.
For the motor something like:
i = 0
while i < 6: # Move 6 times
stepper.Move(0.5) # Moves forward by 0.5 mm
time.sleep(1) # Sleeps for a second
i += 1
time.sleep(2)
print("\nProcess End\n")
close() # closes port
and moves and sleeps as desired.
Both scripts run sucessfully when executed seperately. However, how do I combine these scripts so that I can take a picture at the end of each step? For the example adressed above for moving 6 times, I want to get 6 images at the end, captured at the end of each step. Should one use multithreading, multiprocessing?... Both devices are connected to my computer via 2 seperate USB 2.0 ports. I'm not a beginner in programming, but not an expert either so any suggestions will be kindly appreciated.

It there a reason that you can't call some function that captures an image on each step?
# import modules for camera and stepper control
def step_and_capture(steps=6):
images = []
for x in range(steps):
stepper.Move(0.5)
image = cam_capture_method() # returns a photo or it could write to somewhere
time.sleep(1)
# save the images to folder?
if __name__ == "__main__":
step_and_capture()

Related

How to know what port to take when using multiple cameras with Python and OpenCV

I have been trying to use 3 cameras with Python and OpenCV and I can do it. The problem is that the VideoCapture parameter changes, I've had the idea that it depends on the order of connecting the cameras, being 0 the webcam and external cams starting from 1, but sometimes the webcam turns on with a value different than 0, it gets a bit frustrating after a while and I can't seem to find a solution.
This is the code I have been using to start webcams, the weird thing is that most of the times it pops up the webcam when I dont put a 0, and the external camera opens with the 0.
# Starting Camera 1
self.cap = cv2.VideoCapture(1, cv2.CAP_DSHOW)
self.cap.set(self.FRAME_PROP_WIDTH, self.frame_w)
self.cap.set(self.FRAME_PROP_HEIGHT, self.frame_h)
self.cap.set(cv2.CAP_PROP_FPS,30)
# Starting Camera 2
self.cap = cv2.VideoCapture(2, cv2.CAP_DSHOW)
self.cap.set(self.FRAME_PROP_WIDTH, self.frame_w)
self.cap.set(self.FRAME_PROP_HEIGHT, self.frame_h)
self.cap.set(cv2.CAP_PROP_FPS,30)
# Starting Camera 3
self.cap = cv2.VideoCapture(3, cv2.CAP_DSHOW)
self.cap.set(self.FRAME_PROP_WIDTH, self.frame_w)
self.cap.set(self.FRAME_PROP_HEIGHT, self.frame_h)
self.cap.set(cv2.CAP_PROP_FPS,30)

Pygame camera locks the brightness at -1

Iam trying to use pygame camera to take a picture from my computer cam, but for some reason it always comes out as completely black.
After some research I found out the brightness of the camera (camera.get_controls()) is set to -1 and can't be changed with camera.set_controls()
Code:
# initializing the camera
pygame.camera.init()
# make the list of all available cameras
camlist = pygame.camera.list_cameras()
# if camera is detected or not
if camlist:
# initializing the cam variable with default camera
cam = pygame.camera.Camera(camlist[3], (2952, 1944), "RGB")
# opening the camera
cam.start()
# sets the brightness to 1
cam.set_controls(True, False, 1)
# capturing the single image
image = cam.get_image()
# saving the image
pygame.image.save(image, str(cam.get_controls()) + ".png")
else:
print("No camera on current device")
Pygame.camera tries to be a non blocking API, so it can be used well in a game loop.
The problem is that you open the camera and immediately call get_image(). But no image has been generated yet, so it returns a fully black Surface. Maybe it should be changed on pygame’s end to be a blocking call for the first get_image()
On my system, it works if I put a one second delay before get_image().
You can also use the query_image() function to return if a frame is ready.
*Asterisk: This may differ between operating systems, as it uses different backends on different systems.

Python 3.7 OpenCV - Slow processing

i'm trying to take pictures with OpenCV 4.4.0.40 and only save them if a switch, read by an Arduino, is press.
So far everything work, but it's super slow, it take about 15 seconds for the Switch value to change.
Arduino = SerialObject()
if os.path.exists(PathCouleur) and os.path.exists(PathGris):
Images = cv2.VideoCapture(Camera)
Images.set(3, 1920)
Images.set(4, 1080)
Images.set(10, Brightness)
Compte = 0
SwitchNumero = 0
while True:
Sucess, Video = Images.read()
cv2.imshow("Camera", Video)
Video = cv2.resize(Video, (Largeur, Hauteur))
Switch = Arduino.getData()
try:
if Switch[0] == "1":
blur = cv2.Laplacian(Video, cv2.CV_64F).var()
if blur < MinBlur:
cv2.imwrite(PathCouleur + ".png", Video)
cv2.imwrite(PathGris + ".png", cv2.cvtColor(Video, cv2.COLOR_BGR2GRAY))
Compte += 1
except IndexError as err:
pass
if cv2.waitKey(40) == 27:
break
Images.release()
cv2.destroyAllWindows()
else:
print("Erreur, aucun Path")
the saved images width are 640 and the height is 480 and the showimage is 1920x1080 but even without the showimage it's slow.
Can someone help me optimize this code please?
I would say that this snippet of code is responsible for the delay, since you have two major calls that depend on external devices to respond (the OpenCV calls and Arduino.getData()).
Sucess, Video = Images.read()
cv2.imshow("Camera", Video)
Video = cv2.resize(Video, (Largeur, Hauteur))
Switch = Arduino.getData()
One solution that comes to mind is to use the multithreading lib and separate the Arduino.getData() call from the main loop cycle and use it in a separate class to run in the background (you should use a sleep on the secondary thread, something like 50 or 100ms delay).
That way you should have a better response on the Switch event, when it tries to read the value on the main loop.
cam=cv2.VideoCapture(0,cv2.CAP_DSHOW)
use cv2.CAP_DSHOW it will improve the loading time of camera becasue it wil give you video feed directly

Problem running a python script at boot | raspberry is not connected to a monitor - Raspberry Pi

I have a Raspberry Pi Zero and I am using it to take pictures and measure the luminosity values from a light sensor according to a certain inclination provided by an accelerometer. I want the code to run at start-up without being connected to anything just a power font, maybe an external battery.
The script that I wrote has a loop, and inside the loop takes the values of acceleration from the sensor in the x, y and z direction and calculates the inclination (pitch and roll) using those values. Then it has an if statement that says if the roll and pitch values are within a certain range, takes a picture and saves it in a specific folder and writes the luminosity values inside a text file.
from picamera import PiCamera
import mpu6050library
import tsl2591library
import time
import math
filename = 1
g = 9.8065
camera = PiCamera()
camera.resolution = (1600, 1200)
camera.framerate = 120
camera.rotation = -90
mpu = mpu6050library.mpu6050(0x68)
tsl = tsl2591library.Tsl2591()
while True:
accel_data = mpu.get_accel_data()
ax = accel_data['x']
ay = accel_data['y']
az = accel_data['z']
full, ir = tsl.get_full_luminosity()
lux = tsl.calculate_lux(full, ir)
if (-g < ax < g):
roll = (math.asin(ax/g))*(180/math.pi)
else:
roll = 90.0
if az == 0:
pitch = 90
else:
pitch = math.atan(ay/az)*(180/math.pi)
if ((-18 < roll < 20) and (-18 < pitch < 18)):
camera.capture("/home/pi/RPI2/pictures/" + '%s.jpg' %filename)
file = open("/home/pi/RPI2/lum_values.txt", "a")
file.write("%s" %filename + " - LUX: %s" %lux + " | FULL: %s" %full + " | IR: %s" %ir + "\n")
file.close()
filename = filename + 1
time.sleep(.6)
When I run this code from the Thonny ide, everything works as it should, pictures are saved in the folder and the luminosity values are written in the text file.
I also tried running this code at start-up, using crontab, and having my HDMI cable connected to the rasp and to a monitor, and it also works fine.
The problem begins when I try to run the code at start-up without connecting an HDMI cable and monitor, and powering the rasp with an external battery. Every time I try this, the folder, where the pictures should be, is empty and the text file is also empty. Sometimes it saves only one picture and the text file gets corrupted.
I also tried with a much simpler code, that just takes pictures from time to time and saves it in a folder and the same thing happened. If the HDMI cable is connected to the rasp, I can see the pictures being saved inside the folder, if the HDMI cable is disconnected and I power the rasp with an external battery, once I open the RPI, the folder is empty.
I am not sure, but I think that the problem may be due to the code being runned without the GUI initialized, that happens when I don't connect the HDMI cable.
Do you know what might be the problem here?? And how can I achieved what I want??
Thank you in advance,
Afonso

Kivy graphics with ethernet data reception

My kivy code has to move a widget smoothly linearly from point A to point B and also receive UDP packet via ethernet cable. For now the widget moves smoothly from A to C (C between line AB)and then stops to receive data (may be 0.5 to 1 second) and then the widget moves again.
The movement is not smooth due to this. Any idea how to solve this issue?
I am using socket module from python for data reception.
I even tried thread programming. It did not help, same issue.
class DemoCreator(AnchorLayout):
ev_status = NumericProperty(None) # get ev status(UDP packet)
def receive_ev_status(self):
r = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
r.bind(('', 5555))
prev_data = 0
data, _ = r.recvfrom(1024)
if not data:
data = prev_data
return int.from_bytes(data, 'little')
def update_ev_status(self, dt):
self.ev_status = self.receive_ev_status()
class DemoApp(App):
def build(self):
hmi = DemoCreator()
hmi.map_box.host_car.start((450, 0)
Clock.schedule_interval(hmi.update_ev_status, 0.5)
Clock.schedule_interval(hmi.map_box.update_car, 1 / 60)
return hmi
if __name__ == '__main__':
DemoApp().run()
how to receive data using ports for a kivy application without disturbing its graphics ?
The problem is your use of Clock.schedule_interval() for your ethernet reception. The Clock.schedule family schedules methods to be run on the main thread, so your ethernet work is being done on the same (GUI) thread as your widget motion. That affects the GUI performance. Put your ethernet code in another thread by using something like threading.Thread(target=self.ethernet_recv).start(). The target method will need to do your looping to call your self.receive_ev_status() at 0.5 second intervals.
Have a look at this documentation

Categories

Resources