Skip to content

Commit

Permalink
Switch camera on/off
Browse files Browse the repository at this point in the history
  • Loading branch information
vietanhdev committed Jul 29, 2023
1 parent c5c4fbc commit 794cef1
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 40 deletions.
83 changes: 52 additions & 31 deletions customchar/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ vision::VideoCapture video_capture;
// signal client server ... lock/unlock mutex
constexpr int TEXT_MESSAGE_SIZE = 1024 * 8;
constexpr int INIT_WINDOW_WIDTH = 600;
constexpr int INIT_WINDOW_HEIGHT = 600;
constexpr int INIT_WINDOW_HEIGHT = 400;

static void GLFWErrorCallback(int error, const char* description) {
fprintf(stderr, "Glfw Error %d: %s\n", error, description);
Expand Down Expand Up @@ -105,9 +105,6 @@ void runImgui(std::shared_ptr<session::ChatHistory> history) {
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
(void)io;
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable
// Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; //
// Enable Gamepad Controls

// Setup Dear ImGui style
// ImGui::StyleColorsDark();
Expand All @@ -125,7 +122,7 @@ void runImgui(std::shared_ptr<session::ChatHistory> history) {

// Our state
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
bool justSent = true;
bool just_sent = true;

// Initial text
char text[TEXT_MESSAGE_SIZE] = "";
Expand All @@ -137,6 +134,9 @@ void runImgui(std::shared_ptr<session::ChatHistory> history) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);

bool last_enable_camera = false;
bool enable_camera = true;

// Main loop
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
Expand All @@ -157,26 +157,49 @@ void runImgui(std::shared_ptr<session::ChatHistory> history) {
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);

// Get window size
ImVec2 windowSize = ImGui::GetWindowSize();

// Resize image to fit window
cv::Mat image = video_capture.GetFrame();
cv::Mat resized_image;
float ratio = (float)image.cols / (float)image.rows;
int new_width = windowSize.x;
int new_height = new_width / ratio;
cv::resize(image, resized_image, cv::Size(new_width, new_height));
cv::cvtColor(resized_image, resized_image, cv::COLOR_BGR2RGBA);

// Display image
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, resized_image.cols,
resized_image.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE,
resized_image.data);
ImGui::Image(reinterpret_cast<void*>(static_cast<intptr_t>(texture)),
ImVec2(resized_image.cols, resized_image.rows), ImVec2(0, 0),
ImVec2(1, 1), ImColor(255, 255, 255, 255),
ImColor(255, 255, 255, 128));
ImVec2 window_size = ImGui::GetWindowSize();

// Check and start/stop camera
if (last_enable_camera != enable_camera) {
if (enable_camera) {
video_capture.Start();
// Adapt window height to camera aspect ratio
int window_width = window_size.x;
int window_height = window_width * video_capture.GetFrameHeight() /
video_capture.GetFrameWidth() +
200;
glfwSetWindowSize(window, window_width, window_height);
} else {
video_capture.Stop();
glfwSetWindowSize(window, INIT_WINDOW_WIDTH, INIT_WINDOW_HEIGHT);
}
last_enable_camera = enable_camera;
}

// Render camera
if (enable_camera) {
// Resize image to fit window
cv::Mat image = video_capture.GetFrame();
if (!image.empty()) {
cv::Mat resized_image;
float ratio = (float)image.cols / (float)image.rows;
int new_width = window_size.x - 20;
int new_height = new_width / ratio;
cv::resize(image, resized_image, cv::Size(new_width, new_height));
cv::cvtColor(resized_image, resized_image, cv::COLOR_BGR2RGBA);

// Display image
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, resized_image.cols,
resized_image.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE,
resized_image.data);
ImGui::Image(reinterpret_cast<void*>(static_cast<intptr_t>(texture)),
ImVec2(resized_image.cols, resized_image.rows),
ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255),
ImColor(255, 255, 255, 128));
}
}

ImGui::Checkbox("Enable Camera", &enable_camera);

// Child window scrollable area
ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
Expand All @@ -196,7 +219,7 @@ void runImgui(std::shared_ptr<session::ChatHistory> history) {
ImGui::TextWrapped("> %s: %s", message.GetSender().c_str(),
message.GetMessage().c_str());
}
if (history->HasNewMessage() || justSent) {
if (history->HasNewMessage() || just_sent) {
ImGui::SetScrollHereY(1.0f);
}

Expand All @@ -208,9 +231,9 @@ void runImgui(std::shared_ptr<session::ChatHistory> history) {
ImGuiInputTextFlags input_flags = ImGuiInputTextFlags_ReadOnly;

// Refocus text area if text was just sent
if (justSent) {
if (just_sent) {
ImGui::SetKeyboardFocusHere();
justSent = false;
just_sent = false;
}

// Create a spinner and text input in the same line
Expand All @@ -224,7 +247,7 @@ void runImgui(std::shared_ptr<session::ChatHistory> history) {
strcpy(text, "Say something...");
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputText("##source", text, IM_ARRAYSIZE(text), input_flags)) {
justSent = OnNewMessage(text, "User", history);
just_sent = OnNewMessage(text, "User", history);
};

// Put the cursor of InputTextMultiline at the end of the text
Expand Down Expand Up @@ -272,8 +295,6 @@ int main(int argc, char** argv) {
// Create character
Character character(params);

video_capture.Start();

// Set message callbacks
character.SetOnUserMessage(
std::bind(OnNewMessage, std::placeholders::_1, "User", history));
Expand Down
72 changes: 63 additions & 9 deletions customchar/vision/video_capture.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,60 @@ namespace vision {

class VideoCapture {
private:
int device_id_;
bool is_capturing_;

cv::VideoCapture capture_;
std::mutex capture_mutex_;

cv::Mat frame_;
std::mutex frame_mutex_;
std::thread capture_thread_;

public:
VideoCapture() {
capture_ = cv::VideoCapture(0);
/// @brief Start capturing frames from device
bool StartDevice() {
capture_ = cv::VideoCapture(device_id_);
if (!capture_.isOpened()) {
std::cout << "Error opening video stream or file" << std::endl;
exit(-1);
std::cerr << "Error opening video stream or file" << std::endl;
return false;
} else {
return true;
}
}

/// @brief Stop capturing frames from device
void StopDevice() {
if (capture_.isOpened()) capture_.release();
}

public:
VideoCapture() {}

/// @brief Get frame width
/// @return int
int GetFrameWidth() {
std::lock_guard<std::mutex> lock(frame_mutex_);
return frame_.cols;
}

/// @brief Get frame height
/// @return int
int GetFrameHeight() {
std::lock_guard<std::mutex> lock(frame_mutex_);
return frame_.rows;
}

/// @brief Capture frames from camera
void Capture() {
cv::Mat frame;
while (true) {
capture_ >> frame;
{
std::lock_guard<std::mutex> lock(capture_mutex_);
if (!is_capturing_) {
break;
}
capture_ >> frame;
}
if (frame.empty()) {
break;
}
Expand All @@ -41,10 +76,29 @@ class VideoCapture {
}

/// @brief Start capturing frames
void Start() { capture_thread_ = std::thread(&VideoCapture::Capture, this); }
void Start() {
{
std::lock_guard<std::mutex> lock(capture_mutex_);
if (is_capturing_) {
return;
}
if (!StartDevice()) return;
// Get first frame to initialize frame size
std::lock_guard<std::mutex> frame_lock(frame_mutex_);
capture_ >> frame_;
is_capturing_ = true;
}
capture_thread_ = std::thread(&VideoCapture::Capture, this);
}

/// @brief Stop capturing frames
void Stop() { capture_thread_.join(); }
/// @brief Stop capturing frames
void Stop() {
std::lock_guard<std::mutex> lock(capture_mutex_);
if (!is_capturing_) {
return;
}
StopDevice();
}

/// @brief Get frame from queue
/// @return cv::Mat. Empty if queue is empty
Expand Down

0 comments on commit 794cef1

Please sign in to comment.