Skip to content

Commit

Permalink
Merge main (#14)
Browse files Browse the repository at this point in the history
* Create WebSocket for Webcam Interface (#9)

* Added websocket prototype using websocket++

* Update CXXFLAGS to be more specific

* Update BUILD_GUIDE dependencies

Added 'WebSocket++' and 'boost' to the list of additional dependencies in BUILD_GUIDE.md.

* Remove header files

* Add variables for Websocketpp and Boost libraries

* Update path for Websocketpp and Boost

* Update build guide

* Prevent server from crashing when the client abruptly closes the connection

* Update docs

* Remove std::

* Downgrade to c++17

* Add Build and Test GitHub Action

* Rename workflow

* separated the webcam module into web and webcam modules (#12)

* Webcam Plant Detection (#13)

* changes for webCam

* Added hpp file, minor style fixes, deleted output files

---------
Co-authored-by: emilysxng
Co-authored-by: CihanBosnali <[email protected]>

---------

Co-authored-by: Asad Dhorajiwala <[email protected]>
Co-authored-by: Alfredo-del-Rayo <[email protected]>
Co-authored-by: droy4405 <[email protected]>
  • Loading branch information
4 people authored Jan 10, 2024
1 parent 3dcdb2e commit 1ff732b
Show file tree
Hide file tree
Showing 12 changed files with 311 additions and 29 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Build and Test

on:
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v3

- name: Update Package Index
run: sudo apt-get update

- name: Install Boost
run: sudo apt-get install -y libboost-all-dev

- name: Install OpenCV
run: sudo apt-get install -y libopencv-dev

- name: Install WebSocket++
run: |
git clone --branch 0.8.2 https:/zaphoyd/websocketpp.git
sudo cp -r ./websocketpp/websocketpp ./include
- name: Build project
run: make

test:
needs: build

runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Run tests
run: make test_ALL
2 changes: 2 additions & 0 deletions BUILD_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
additional dependencies include:
- `librealsense2` \[v.2.54.2\] - to drive the distance sensing camera
- `opencv` \[v.4.8.1\] - to process images from the camera
- `WebSocket++` \[v.0.8.2\] - to create a websocket server
- `boost` \[v.1.83.0\] - required by `WebSocket++`

### Build Commands
In a linux shell, the following rules have been provided via the build system:
Expand Down
5 changes: 4 additions & 1 deletion config.mk
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
WEBSOCKETPP_DIR := /path/to/websocketpp/include
BOOST_DIR := /path/to/boost/include

TARGET_FOLDER := build
INCLUDE_DIRS := $(ROOT_DIR)/include
SRC_DIR := $(ROOT_DIR)/src
Expand All @@ -6,7 +9,7 @@ BUILD_DIR := $(ROOT_DIR)/build
OBJS_DIR := $(BUILD_DIR)/objs

CXX := g++
CXXFLAGS := -std=c++20 -Wall `pkg-config --cflags opencv4`
CXXFLAGS := -std=c++17 -Wall `pkg-config --cflags opencv4` -I ${WEBSOCKETPP_DIR} -I $(BOOST_DIR)
LINK_TIME_FLAGS :=
LIBS := `pkg-config --libs opencv4`

Expand Down
42 changes: 42 additions & 0 deletions include/RealIntelCam.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef INTELCAM_H
#define INTELCAM_H

#include <librealsense2/rs.hpp>
#include <iostream>
#include <vector>
#include <cmath>

const float TIME_INTERVAL = 0.01; // Time interval in seconds
const double RAD_TO_DEG = 180.0 / M_PI;


using namespace std

class realIntelCam
{
public:

RealIntelCam();

void update_camera_position();

vector<float> get_location();

vector<float> get_angle();

private:
//Essential to initiate connection
rs2::pipeline pipeline;
rs2::config configure;
rs2::pipeline_profile profile;
// the acceleration in 3D previous: 0->x, 1->y, 2->z current 3->x, 4->y, 5->z
float acceleration[]{};
// average velocity aka speed
float velocity[]{};
// calculated location
float camera_location[];
//calculated angle
float camera_angle[];
}

#endif
6 changes: 6 additions & 0 deletions include/web_interface.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef WEB_INTERFACE_HPP
#define WEB_INTERFACE_HPP

int web(Mat *frame);

#endif // WEBCAM_INTERFACE_HPP
9 changes: 9 additions & 0 deletions include/webcamPlantDetection.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef WEBCAMPLANTDETECTION_HPP
#define WEBCAMPLANTDETECTION_HPP

#include <opencv2/opencv.hpp>
using namespace cv;

Mat isGreen(const Mat& image);

#endif
9 changes: 9 additions & 0 deletions make.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
build_/mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/src/sample_submodule build_/mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/src/grass_killer build_/mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/src/imu_interface
mkdir -p /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs
mkdir -p /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build
g++ -I /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/include -c /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/src/sample_submodule/submodule.cpp -o /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs/submodule.o
g++ -I /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/include -c /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/src/sample_submodule/arg.cpp -o /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs/arg.o
g++ -I /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/include -c /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/src/grass_killer/grass_killer.cpp -o /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs/grass_killer.o
g++ -I /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/include -c /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/src/imu_interface/measure.cpp -o /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs/measure.o
[[[[ BUILDING NAVI ]]]]
g++ /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs/main.o /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs/submodule.o /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs/arg.o /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs/grass_killer.o /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/build/objs/measure.o -o /mnt/c/Users/adelr/Documents/Agrobot/new-intel-realsense-imu-interface-Alfredo/.git/Navi/navi
9 changes: 9 additions & 0 deletions src/WebcamPlantDetection/rules.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
GENERATED_OBJS := webcamPlantDetection.o

include submodule.general.mk

build_$(DIR):
$(call build,webcamPlantDetection.cpp)
clean_$(DIR):
test_$(DIR):
@echo testing the module $(DIR)!
34 changes: 34 additions & 0 deletions src/WebcamPlantDetection/webcamPlantDetection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

Mat isGreen(const Mat& image) {
Mat hsvImage;
Mat mask;
Scalar lower(35, 60, 60);
Scalar upper(80, 255, 255);
cvtColor(image, hsvImage, COLOR_RGB2HSV);
inRange(hsvImage, lower, upper, mask);
return mask;
}

int test_isGreen() {
Mat myImage;
VideoCapture cap(0);
if (!cap.isOpened())
return 5; // IO Error Code on Linux, Access Denied Error Code on Windows

while (true) {
cap >> myImage;
if (myImage.empty())
break;
Mat greenMask = isGreen(myImage);
imshow("Video Player", greenMask);
char c = (char)waitKey(25);
if (c == 27)
break;
}
cap.release();
return 0;
}
10 changes: 10 additions & 0 deletions src/web_interface/rules.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
GENERATED_OBJS := web_interface.o

include submodule.general.mk

build_$(DIR):
$(call build,web_interface.cpp)
clean_$(DIR):
test_$(DIR):
@echo testing the module $(DIR)!
test_webcam_interface: test_$(DIR)
69 changes: 69 additions & 0 deletions src/web_interface/web_interface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <thread>

using namespace std;
using namespace cv;

// Alias for websocketpp server
typedef websocketpp::server<websocketpp::config::asio> server;

/*!
* Handles the connection to the WebSocket server.
* Captures frames from the webcam, encodes them,
* and sends them via the WebSocket connection.
*
* \param hdl The connection handle.
* \param s The WebSocket server.
* \param cap The OpenCV VideoCapture object.
*/
void handle_connection(websocketpp::connection_hdl hdl, server& s, Mat *frame) {
while (true) {
try {
if (!frame->empty()) {
// Convert OpenCV frame to byte vector
vector<uchar> buffer;
imencode(".jpg", *frame, buffer);
s.send(hdl, buffer.data(), buffer.size(), websocketpp::frame::opcode::binary);
}
else {
cerr << "Couldn't capture frame from webcam." << endl;
break;
}
} catch (websocketpp::exception const & e) {
cout << "Caught websocket exception: " << e.what() << endl;
}
}
}

/*!
* Initializes and runs the WebSocket server, capturing frames
* from the webcam and sending them via open WebSocket connections.
*
* Clears all access log channels, initializes the OpenCV webcam,
* defines the WebSocket server connection handler, listens on port 6969,
* and finally starts the accept loop and the ASIO io_service event loop.
*
* \return 0 if the server ran successfully, otherwise -1.
*/
int web(Mat *frame) {
// Create a WebSocket server
server s;
// Clear all access log channels to prevent frames being logged
// If frames are logged, then it makes the WebSocket server very slow
s.clear_access_channels(websocketpp::log::alevel::all);

s.set_open_handler([&s,frame](websocketpp::connection_hdl hdl) {
thread video_thread(handle_connection, hdl, ref(s), ref(frame));
video_thread.detach();
});

// Listen on port 6969
s.init_asio();
s.listen(6969);
s.start_accept();
s.run();

return 0;
}

106 changes: 78 additions & 28 deletions src/webcam_interface/webcam_interface.cpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,85 @@
#include<opencv2/opencv.hpp>
#include<iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <opencv2/opencv.hpp>
#include <thread>

using namespace std;
using namespace cv;

// Alias for websocketpp server
typedef websocketpp::server<websocketpp::config::asio> server;

/*!
* @brief Opens and displays the webcam video feed until termination.
* @return Returns 0 upon successful completion, else returns -1.
* Handles the connection to the WebSocket server.
* Captures frames from the webcam, encodes them,
* and sends them via the WebSocket connection.
*
* \param hdl The connection handle.
* \param s The WebSocket server.
* \param cap The OpenCV VideoCapture object.
*/
void handle_connection(websocketpp::connection_hdl hdl, server& s, VideoCapture& cap) {
try {
while (true) {
// Read frame from webcam
Mat frame;
cap >> frame;

// Check if frame is empty
if (!frame.empty()) {
// Convert OpenCV frame to byte vector
vector<uchar> buffer;
imencode(".jpg", frame, buffer);

// Send the frame as a binary message via WebSocket
s.send(hdl, buffer.data(), buffer.size(), websocketpp::frame::opcode::binary);
}
else {
cerr << "Couldn't capture frame from webcam." << endl;
break;
}
}
} catch (websocketpp::exception const & e) {
cout << "Caught websocket exception: " << e.what() << endl;
}
}

/*!
* Initializes and runs the WebSocket server, capturing frames
* from the webcam and sending them via open WebSocket connections.
*
* Clears all access log channels, initializes the OpenCV webcam,
* defines the WebSocket server connection handler, listens on port 6969,
* and finally starts the accept loop and the ASIO io_service event loop.
*
* \return 0 if the server ran successfully, otherwise -1.
*/
int webcam() {
Mat myImage;
namedWindow("Webcam Video Feed");
VideoCapture cap(0);

if (!cap.isOpened()) {
cout << "No webcam feed detected" << endl;
system("pause");
return -1;
}

while (true) {
cap >> myImage;
if (myImage.empty()) {
break;
}

imshow("Webcam Video Feed", myImage);
char c = (char)waitKey(25);
if (c == 27) {
break;
}
}
cap.release();
return 0;
// Create a WebSocket server
server s;

// Clear all access log channels to prevent frames being logged
// If frames are logged, then it makes the WebSocket server very slow
s.clear_access_channels(websocketpp::log::alevel::all);

// Initialize OpenCV webcam
VideoCapture cap(0);
if (!cap.isOpened()) {
cerr << "Couldn't open the webcam." << endl;
return -1;
}

// Define WebSocket server connection handler
s.set_open_handler([&s, &cap](websocketpp::connection_hdl hdl) {
thread video_thread(handle_connection, hdl, ref(s), ref(cap));
video_thread.detach();
});

// Listen on port 6969
s.init_asio();
s.listen(6969);
s.start_accept();
s.run();

return 0;
}

0 comments on commit 1ff732b

Please sign in to comment.