윗 프로젝트는 원래 Raspberry Pi용으로 만들어져서 PiCam라이브러리를 사용하기 때문에 일반 리눅스 용으로 사용하기에는 불편한데, 코드를 일반 Linux의 USB Cam 용으로 바꿨습니다.
첫 코드 1_test.py를 바꾼 내용을 올립니다. 이 코드와 저 사이트에서 다운받는 코드를 비교해 보면 나머지도 어떻게 바꾸는 지 쉽게 나옵니다. 그리고 초저가 USB Dual CAM 이 Dual 파이 캠보다 사용이 훨씬 좋고 resize를 안해서 속도도 훨씬 빨랐습니다.
바뀐 1_test.py
# Modified by 현자 to work with non-Raspberry Pi PC's
# Cam used: OV9732 Binocular Sync Camera Module, 72 Degree, 1 Million Pixel
import time
import cv2
import os
from datetime import datetime
# File for captured image
filename = './scenes/photo.png'
# Camera settimgs (at 640x240, its default frame rate = 25)
cam_width = 640 # Width must be dividable by 32
cam_height = 240 # Height must be dividable by 16
print ("Camera Resolution: "+str(cam_width)+" x "+str(cam_height))
# Initialize the camera
camera = cv2.VideoCapture(0)
# Must set camera WORKING camera resolution to get Left/Right side by side
camera.set(cv2.CAP_PROP_FRAME_WIDTH, cam_width)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, cam_height)
t2 = datetime.now()
counter = 0
avgtime = 0
# Capture frames from the camera
while camera.isOpened():
ret, frame = camera.read()
counter+=1
t1 = datetime.now()
timediff = t1-t2
avgtime = avgtime + (timediff.total_seconds())
cv2.imshow("Both Eyes", frame)
key = cv2.waitKey(1) & 0xFF
t2 = datetime.now()
# if the `q` key was pressed, break from the loop and save last image
if key == ord("q") :
avgtime = avgtime/counter
print ("Average time between frames: " + str(avgtime))
print ("Average FPS: " + str(1/avgtime))
if (os.path.isdir("./scenes")==False):
os.makedirs("./scenes")
cv2.imwrite(filename, frame)
break
camera.release()
바뀐 2_chess_cycle.py
# Copyright (C) 2019 Eugene Pomazov, <stereopi.com>, virt2real team
#
# This file is part of StereoPi tutorial scripts.
#
# StereoPi tutorial is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# StereoPi tutorial is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with StereoPi tutorial.
# If not, see <http://www.gnu.org/licenses/>.
#
# Most of this code is updated version of 3dberry.org project by virt2real
#
# Thanks to Adrian and http://pyimagesearch.com, as there are lot of
# code in this tutorial was taken from his lessons.
#
# ================================================
# Modified by 현자 to work with non-Raspberry Pi PC's
# Cam used: OV9732 Binocular Sync Camera Module, 72 Degree, 1 Million Pixel
import os
import time
from datetime import datetime
import cv2
import numpy as np
# Photo session settings
total_photos = 30 # Number of images to take
countdown = 5 # Interval for count-down timer, seconds
font=cv2.FONT_HERSHEY_SIMPLEX # Cowntdown timer font
# Camera settimgs (at 640x240, its default frame rate = 25)
cam_width = 640 # Width must be dividable by 32
cam_height = 240 # Height must be dividable by 16
#capture = np.zeros((img_height, img_width, 4), dtype=np.uint8)
print ("Final resolution: "+str(cam_width)+" x "+str(cam_height))
# Initialize the camera
camera = cv2.VideoCapture(0)
# Must set camera WORKING camera resolution to get Left/Right side by side
camera.set(cv2.CAP_PROP_FRAME_WIDTH, cam_width)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, cam_height)
# Lets start taking photos!
counter = 0
t2 = datetime.now()
print ("Starting photo sequence")
while camera.isOpened():
ret, frame = camera.read()
t1 = datetime.now()
cntdwn_timer = countdown - int ((t1-t2).total_seconds())
# If cowntdown is zero - let's record next image
if cntdwn_timer == -1:
counter += 1
filename = './scenes/scene_'+str(cam_width)+'x'+str(cam_height)+'_'+\
str(counter) + '.png'
cv2.imwrite(filename, frame)
print (' ['+str(counter)+' of '+str(total_photos)+'] '+filename)
t2 = datetime.now()
time.sleep(1)
cntdwn_timer = 0 # To avoid "-1" timer display
next
# Draw cowntdown counter, seconds
cv2.putText(frame, str(cntdwn_timer), (50,50), font, 2.0, (0,0,255),4, cv2.LINE_AA)
cv2.imshow("pair", frame)
key = cv2.waitKey(1) & 0xFF
# Press 'Q' key to quit, or wait till all photos are taken
if (key == ord("q")) | (counter == total_photos):
break
print ("Photo sequence finished")
camera.release()
아래 화일들은 카메라를 열지 않기때문에 바뀔 필요가 없습니다.
3_pairs_cut.py
4_calibration.py
5_dm_tune.py
바뀐 6_dm_video.py
# Copyright (C) 2019 Eugene Pomazov, <stereopi.com>, virt2real team
#
# This file is part of StereoPi tutorial scripts.
#
# StereoPi tutorial is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# StereoPi tutorial is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with StereoPi tutorial.
# If not, see <http://www.gnu.org/licenses/>.
#
# Most of this code is updated version of 3dberry.org project by virt2real
#
# Thanks to Adrian and http://pyimagesearch.com, as there are lot of
# code in this tutorial was taken from his lessons.
#
# ================================================
# Modified by 현자 to work with non-Raspberry Pi PC's
# Cam used: OV9732 Binocular Sync Camera Module, 72 Degree, 1 Million Pixel
import time
import cv2
import numpy as np
import json
from stereovision.calibration import StereoCalibrator
from stereovision.calibration import StereoCalibration
from datetime import datetime
# Depth map default preset
SWS = 5
PFS = 5
PFC = 29
MDS = -30
NOD = 160
TTH = 100
UR = 10
SR = 14
SPWS = 100
# Camera settimgs (at 640x240, its default frame rate = 25)
cam_width = 640 # Width must be dividable by 32
cam_height = 240 # Height must be dividable by 16
#capture = np.zeros((img_height, img_width, 4), dtype=np.uint8)
print ("Final resolution: "+str(cam_width)+" x "+str(cam_height))
# Initialize the camera
camera = cv2.VideoCapture(0)
# Must set camera WORKING camera resolution to get Left/Right side by side
camera.set(cv2.CAP_PROP_FRAME_WIDTH, cam_width)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, cam_height)
# Implementing calibration data
print('Read calibration data and rectifying stereo pair...')
calibration = StereoCalibration(input_folder='calib_result')
# Initialize interface windows
cv2.namedWindow("Image")
cv2.moveWindow("Image", 50,100)
cv2.namedWindow("left")
cv2.moveWindow("left", 450,100)
cv2.namedWindow("right")
cv2.moveWindow("right", 850,100)
disparity = np.zeros((cam_width, cam_height), np.uint8)
sbm = cv2.StereoBM_create(numDisparities=0, blockSize=21)
def stereo_depth_map(rectified_pair):
dmLeft = rectified_pair[0]
dmRight = rectified_pair[1]
disparity = sbm.compute(dmLeft, dmRight)
local_max = disparity.max()
local_min = disparity.min()
disparity_grayscale = (disparity-local_min)*(65535.0/(local_max-local_min))
disparity_fixtype = cv2.convertScaleAbs(disparity_grayscale, alpha=(255.0/65535.0))
disparity_color = cv2.applyColorMap(disparity_fixtype, cv2.COLORMAP_JET)
cv2.imshow("Image", disparity_color)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
quit();
return disparity_color
def load_map_settings( fName ):
global SWS, PFS, PFC, MDS, NOD, TTH, UR, SR, SPWS, loading_settings
print('Loading parameters from file...')
f=open(fName, 'r')
data = json.load(f)
SWS=data['SADWindowSize']
PFS=data['preFilterSize']
PFC=data['preFilterCap']
MDS=data['minDisparity']
NOD=data['numberOfDisparities']
TTH=data['textureThreshold']
UR=data['uniquenessRatio']
SR=data['speckleRange']
SPWS=data['speckleWindowSize']
#sbm.setSADWindowSize(SWS)
sbm.setPreFilterType(1)
sbm.setPreFilterSize(PFS)
sbm.setPreFilterCap(PFC)
sbm.setMinDisparity(MDS)
sbm.setNumDisparities(NOD)
sbm.setTextureThreshold(TTH)
sbm.setUniquenessRatio(UR)
sbm.setSpeckleRange(SR)
sbm.setSpeckleWindowSize(SPWS)
f.close()
print ('Parameters loaded from file '+fName)
load_map_settings ("3dmap_set.txt")
# capture frames from the camera
while camera.isOpened():
ret, frame = camera.read()
t1 = datetime.now()
pair_img = cv2.cvtColor (frame, cv2.COLOR_BGR2GRAY)
imgLeft = pair_img [0:cam_height,0:int(cam_width/2)] #Y+H and X+W
imgRight = pair_img [0:cam_height,int(cam_width/2):cam_width] #Y+H and X+W
rectified_pair = calibration.rectify((imgLeft, imgRight))
disparity = stereo_depth_map(rectified_pair)
# show the frame
cv2.imshow("left", imgLeft)
cv2.imshow("right", imgRight)
t2 = datetime.now()
print ("DM build time: " + str(t2-t1))
camera.release()
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
#define _CIRCLE_RAD 10
// (PIN NO) - 4 PhotoResistors (Front, Back, Left, Right)
const int prFrontPin = 36; // default A/D
const int prBackPin = 39; // default A/D
const int prLeftPin = 2; // (*) this analog port dies if Wifi is enabled
const int prRightPin = 14; // (*) this analog port dies if Wifi is enabled
// Also need to call on setup() to enable as A/D. "adcAttachPin(prLeftPin)";
// Also need to call on setup() to enable as A/D. "adcAttachPin(prRightPin)";
/* PROBLEM WITH ESP32 A/D : GPIO25, GPIO26, GPIO4, GPIO0 did not work as A/D */
// For Two Buttons
const int btnRUN = 13; // Run
const int btnTraining = 15; // Training Neural Network
bool IsRunning = false;
bool IsTraining = false;
// For TB6612FNG Motor Driver
// Currently problem with short number of pins, I will use GPIO16 for all following
// three pins on motor controller to put it HIGH,
// Will not use PWM, since this board sucks, and PWM has too much trouble.
// The OLED board that I used for this project is by far worst in all the ESP32 boards that I have used so far.
const int md_STBY_pin = 16; // Enables whole motor drive.
const int md_A_PWM_pin = 16; // Speed of Motor A
const int md_B_PWM_pin = 16; // Speed of Motor B
// I can disable motor A by in1 & in2 both LOW
const int md_AIN1_pin = 26; // Direction of Motor A
const int md_AIN2_pin = 0; // Direction of Motor A
// I can disable motor B by in1 & in2 both LOW
const int md_BIN1_pin = 12; // Direction of Motor B
const int md_BIN2_pin = 25; // Direction of Motor B
// (VALUES) 4 PhotoResistors (Front, Back, Left, Right)
int prFrontValue = 0;
int prBackValue = 0;
int prLeftValue = 0;
int prRightValue = 0;
SSD1306Wire display(0x3c, 5, 4);
int MotorTestL = 0; // 0 : stop, 1 : Forward, 2 : Backward
int MotorTestR = 0; // 0 : stop, 1 : Forward, 2 : Backward
const int WheelLeft = 32; // motor L on my design sheet
const int WheelRight = 27; // motor R on my design sheet
int r = 0; // Simple Counter to replace delay() in the main loop
String s; // Temporary string for general purpose
String sendbuff;
String commandstring;
String cs = ""; // Command String
String rs = ""; // Respond String = 'R' + Command String
char ReplyBuffer[] = "acknowledged"; // a string to send back
unsigned long preMillis = 0;
unsigned long curMillis = 0;
void drawTop(void) {
display.drawCircle(10, display.getHeight()/2, _CIRCLE_RAD);
display.display();
}
void drawBottom(void) {
display.drawCircle(50, display.getHeight()/2, _CIRCLE_RAD);
display.display();
}
void drawLeft(void) {
display.drawCircle(30, display.getHeight()-12, _CIRCLE_RAD);
display.display();
}
void drawRight(void) {
display.drawCircle(30, 10, _CIRCLE_RAD);
display.display();
}
void drawTest() {
display.init();
display.setContrast(255);
display.clear();
display.display();
delay(1000);
drawTop();
delay(500);
drawBottom();
delay(500);
drawLeft();
delay(500);
drawRight();
delay(500);
}
void IRAM_ATTR onRunPressed() {
if (IsRunning == false) {
Serial.println("RUN");
IsRunning = true;
} else {
Serial.println("OFF RUN");
}
MotorTestL += 1;
if (MotorTestL > 2) { MotorTestL = 0; }
}
void IRAM_ATTR onTrainingPressed() {
if (IsTraining == false) {
Serial.println("TRAINING");
IsTraining = true;
} else {
Serial.println("OFF TRAINING");
}
MotorTestR += 1;
if (MotorTestR > 2) { MotorTestR = 0; }
}
void turn_right() { // Turn Right
digitalWrite(md_AIN1_pin, HIGH);
digitalWrite(md_AIN2_pin, LOW);
digitalWrite(md_BIN1_pin, LOW);
digitalWrite(md_BIN2_pin, HIGH);
}
void turn_left() { // Turn Left
digitalWrite(md_AIN1_pin, LOW);
digitalWrite(md_AIN2_pin, HIGH);
digitalWrite(md_BIN1_pin, HIGH);
digitalWrite(md_BIN2_pin, LOW);
}
void move_forward() { //
digitalWrite(md_AIN1_pin, HIGH);
digitalWrite(md_AIN2_pin, LOW);
digitalWrite(md_BIN1_pin, HIGH);
digitalWrite(md_BIN2_pin, LOW);
}
void move_backward() { //
digitalWrite(md_AIN1_pin, LOW);
digitalWrite(md_AIN2_pin, HIGH);
digitalWrite(md_BIN1_pin, LOW);
digitalWrite(md_BIN2_pin, HIGH);
}
void wheel_stop() {
digitalWrite(md_AIN1_pin, LOW);
digitalWrite(md_AIN2_pin, LOW);
digitalWrite(md_BIN1_pin, LOW);
digitalWrite(md_BIN2_pin, LOW);
}
void setup() {
r = 0;
pinMode(btnRUN, INPUT); // BUTTON B1
pinMode(btnTraining, INPUT); // BUTTON B2
attachInterrupt(btnRUN, onRunPressed, RISING);
attachInterrupt(btnTraining, onTrainingPressed, RISING);
pinMode(md_STBY_pin, OUTPUT); // 16; // (6 will CRASH) Enables whole motor drive.
pinMode(md_AIN1_pin, OUTPUT); // 26;// Direction of Motor A
pinMode(md_AIN2_pin, OUTPUT); // 0; // Direction of Motor A
// pinMode(md_A_PWM_pin, OUTPUT);// 16; // Speed of Motor A
pinMode(md_BIN1_pin, OUTPUT); // 12;// Direction of Motor A
pinMode(md_BIN2_pin, OUTPUT); // 25; // Direction of Motor A
// pinMode(md_B_PWM_pin, OUTPUT);// 16; // Speed of Motor A
Serial.begin(112500);
drawTest();
adcAttachPin(prLeftPin);
adcAttachPin(prRightPin);
digitalWrite(md_STBY_pin, HIGH); // it will make ON for both PWMA, PWMB also
// digitalWrite(md_A_PWM_pin, HIGH);
// digitalWrite(md_B_PWM_pin, HIGH);
move_forward(); delay(1000);
wheel_stop(); delay(1000);
move_backward(); delay(1000);
wheel_stop(); delay(1000);
turn_right(); delay(1000);
wheel_stop(); delay(1000);
turn_left(); delay(1000);
wheel_stop(); delay(1000);
}
void loop() {
r++;
if (r > 650000){ // THIS IS DESCENT DELAY // about 1 sec
prFrontValue = analogRead(prFrontPin); // delay in between reads for stability
prBackValue = analogRead(prBackPin); // delay in between reads for stability
prLeftValue = analogRead(prLeftPin); // delay in between reads for stability
prRightValue = analogRead(prRightPin); // delay in between reads for stability
// delay(50); // delay in between reads for stability
s = " ";
s += prFrontValue;
s += ", ";
s += prBackValue;
s += ", ";
s += prLeftValue;
s += ", ";
s += prRightValue;
Serial.println(s);
r = 0;
}
}
WorkFocusClock.exe 는 요즘 유행하는 Deadline Driven Development (마감시간에 쫒기는 듯 개발하기?) 에 사용하기 편하도록 아주 단순하게 만들어진 PC용 모래시계입니다.
이 프로그램은 PC에 어떤 화일도 생성하거나 고치지 않고 네트웍을 사용하지 않고 윈도우 자체에 따라오는 딱 3개의 음악 wav 화일만 알람용으로 읽기 전용으로 사용합니다. 그래서 따로 사용자 세팅을 저장하지 않습니다. 도움말도 없고 무지무지 단순하게 몇시간만에 뚝딱뚝딱 만든 공유하기도 민망한 프로그램인데 나름 쓸만 하더군요.
진짜 모래시계는 시간을 못바꾸는데 이건 시간을 그냥 마음대로 지정해 줄 수 있고 단순하게라도 집중할 내용을 간단하게 적어놓을수 있게 만들었습니다.