Inital commit
This commit is contained in:
		
						commit
						89cd91d935
					
				
					 5 changed files with 850 additions and 0 deletions
				
			
		
							
								
								
									
										33
									
								
								CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
cmake_minimum_required(VERSION 3.6)
 | 
			
		||||
 | 
			
		||||
project(uvoscam)
 | 
			
		||||
 | 
			
		||||
set(SRC_FILES uvoscam.cpp)
 | 
			
		||||
 | 
			
		||||
find_package(PkgConfig REQUIRED)
 | 
			
		||||
find_package(OpenCV REQUIRED)
 | 
			
		||||
pkg_check_modules(GLIB REQUIRED glib-2.0)
 | 
			
		||||
pkg_check_modules(ARAVIS REQUIRED aravis-0.8)
 | 
			
		||||
 | 
			
		||||
add_library(${PROJECT_NAME} SHARED ${SRC_FILES})
 | 
			
		||||
target_link_libraries( ${PROJECT_NAME} ${GLIB_LDFLAGS} ${ARAVIS_LDFLAGS} ${OpenCV_LIBS} -pthread)
 | 
			
		||||
target_include_directories(${PROJECT_NAME} PRIVATE ${GLIB_INCLUDE_DIRS} ${ARAVIS_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})
 | 
			
		||||
add_definitions("-std=c++17 -Wall -O2")
 | 
			
		||||
install(TARGETS ${PROJECT_NAME} DESTINATION lib)
 | 
			
		||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
 | 
			
		||||
 | 
			
		||||
link_directories(${CMAKE_CURRENT_BINARY_DIR})
 | 
			
		||||
 | 
			
		||||
add_executable(${PROJECT_NAME}_cli main.cpp)
 | 
			
		||||
add_dependencies(${PROJECT_NAME}_cli ${PROJECT_NAME})
 | 
			
		||||
target_include_directories(${PROJECT_NAME}_cli PRIVATE ${ARAVIS_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})
 | 
			
		||||
target_link_libraries( ${PROJECT_NAME}_cli -l${PROJECT_NAME} ${OpenCV_LIBS})
 | 
			
		||||
target_link_libraries( ${PROJECT_NAME}_cli)
 | 
			
		||||
add_definitions("-std=c++17 -Wall -O2")
 | 
			
		||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
set(CMAKE_INSTALL_PREFIX "/usr")
 | 
			
		||||
install(TARGETS ${PROJECT_NAME}_cli RUNTIME DESTINATION bin)
 | 
			
		||||
install(TARGETS ${PROJECT_NAME} DESTINATION lib)
 | 
			
		||||
install(FILES ./uvoscam.h DESTINATION include)
 | 
			
		||||
							
								
								
									
										95
									
								
								log.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								log.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,95 @@
 | 
			
		|||
/**
 | 
			
		||||
* Lubricant Detecter
 | 
			
		||||
* Copyright (C) 2021 Carl Klemm
 | 
			
		||||
*
 | 
			
		||||
* This program is free software; you can redistribute it and/or
 | 
			
		||||
* modify it under the terms of the GNU General Public License
 | 
			
		||||
* version 3 as published by the Free Software Foundation.
 | 
			
		||||
*
 | 
			
		||||
* This program 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 this program; if not, write to the
 | 
			
		||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 | 
			
		||||
* Boston, MA  02110-1301, USA.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
class Log 
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	
 | 
			
		||||
	enum Level
 | 
			
		||||
	{
 | 
			
		||||
		DEBUG,
 | 
			
		||||
		INFO,
 | 
			
		||||
		WARN,
 | 
			
		||||
		ERROR
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	bool opened = false;
 | 
			
		||||
	Level msglevel = DEBUG;
 | 
			
		||||
 | 
			
		||||
	inline std::string getLabel(Level level) 
 | 
			
		||||
	{
 | 
			
		||||
		std::string label;
 | 
			
		||||
		switch(level) 
 | 
			
		||||
		{
 | 
			
		||||
			case DEBUG: 
 | 
			
		||||
				label = "DEBUG"; 
 | 
			
		||||
				break;
 | 
			
		||||
			case INFO:  
 | 
			
		||||
				label = "INFO "; 
 | 
			
		||||
				break;
 | 
			
		||||
			case WARN:  
 | 
			
		||||
				label = "WARN "; 
 | 
			
		||||
				break;
 | 
			
		||||
			case ERROR: 
 | 
			
		||||
				label = "ERROR"; 
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
		return label;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	inline static bool headers = false;
 | 
			
		||||
	inline static Level level = WARN;
 | 
			
		||||
 | 
			
		||||
	Log() {}
 | 
			
		||||
	Log(Level type)
 | 
			
		||||
	{
 | 
			
		||||
		msglevel = type;
 | 
			
		||||
		if(headers) 
 | 
			
		||||
		{
 | 
			
		||||
			operator << ("["+getLabel(type)+"]");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	~Log() 
 | 
			
		||||
	{
 | 
			
		||||
		if(opened) 
 | 
			
		||||
		{
 | 
			
		||||
			std::cout<<'\n';
 | 
			
		||||
		}
 | 
			
		||||
		opened = false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	template<class T> Log &operator<<(const T &msg) 
 | 
			
		||||
	{
 | 
			
		||||
		if(msglevel >= level) 
 | 
			
		||||
		{
 | 
			
		||||
			std::cout<<msg;
 | 
			
		||||
			opened = true;
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										140
									
								
								main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								main.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,140 @@
 | 
			
		|||
/**
 | 
			
		||||
* Cam
 | 
			
		||||
* Copyright (C) 2021 Carl Klemm
 | 
			
		||||
*
 | 
			
		||||
* This program is free software; you can redistribute it and/or
 | 
			
		||||
* modify it under the terms of the GNU General Public License
 | 
			
		||||
* version 3 as published by the Free Software Foundation.
 | 
			
		||||
*
 | 
			
		||||
* This program 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 this program; if not, write to the
 | 
			
		||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 | 
			
		||||
* Boston, MA  02110-1301, USA.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <math.h> 
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <opencv2/imgcodecs.hpp>
 | 
			
		||||
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "uvoscam.h"
 | 
			
		||||
 | 
			
		||||
#define VERSION "0.1"
 | 
			
		||||
 | 
			
		||||
using namespace cam;
 | 
			
		||||
 | 
			
		||||
static std::string filename;
 | 
			
		||||
 | 
			
		||||
void listDevices()
 | 
			
		||||
{
 | 
			
		||||
	std::vector<Camera::Description> cameras = Camera::getAvailableCameras();
 | 
			
		||||
	size_t i = 0;
 | 
			
		||||
	for(auto camera : cameras)
 | 
			
		||||
		std::cout<<i++<<": "<<camera.id<<' '<<camera.model<<' '<<camera.vendor<<'\n';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void help()
 | 
			
		||||
{
 | 
			
		||||
	std::cout<<"Avaiable commands:\n"
 | 
			
		||||
	         <<"help            Displays this message\n"
 | 
			
		||||
	         <<"list            Lists cameras found\n"
 | 
			
		||||
	         <<"open [name]     Open camera with string name\n"
 | 
			
		||||
	         <<"close           Close camera \n"
 | 
			
		||||
	         <<"capture [file]  Take an image and save it to file\n"
 | 
			
		||||
	         <<"exit            Quit program\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void callback(cv::Mat data)
 | 
			
		||||
{
 | 
			
		||||
	Log(Log::INFO)<<"Saveing image";
 | 
			
		||||
	cv::imwrite("./testimg.png", data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<std::string> tokenize(const std::string& in, char delim = ' ')
 | 
			
		||||
{
 | 
			
		||||
	std::vector<std::string> vect;
 | 
			
		||||
	std::stringstream ss(in);
 | 
			
		||||
	
 | 
			
		||||
	for(std::string token; std::getline(ss, token, delim);)
 | 
			
		||||
		vect.push_back(token);
 | 
			
		||||
	return vect;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char* argv[])
 | 
			
		||||
{	
 | 
			
		||||
	Camera camera(callback);
 | 
			
		||||
	
 | 
			
		||||
	Log::level = Log::DEBUG;
 | 
			
		||||
	
 | 
			
		||||
	Log(Log::INFO)<<"UVOS Camera capture program "<<VERSION;
 | 
			
		||||
 | 
			
		||||
	while(true)
 | 
			
		||||
	{
 | 
			
		||||
		std::cout<<"> ";
 | 
			
		||||
		std::string line;
 | 
			
		||||
		std::getline(std::cin, line);
 | 
			
		||||
		std::vector<std::string> tokens = tokenize(line);
 | 
			
		||||
		
 | 
			
		||||
		int ret = -1;
 | 
			
		||||
		
 | 
			
		||||
		if(!tokens.empty())
 | 
			
		||||
		{
 | 
			
		||||
			if(tokens[0].find("help") != std::string::npos)
 | 
			
		||||
				help();
 | 
			
		||||
			else if(tokens[0].find("exit") != std::string::npos ||  tokens[0].find("quit") != std::string::npos)
 | 
			
		||||
				break;
 | 
			
		||||
			else if(tokens[0].find("list") != std::string::npos)
 | 
			
		||||
				listDevices();
 | 
			
		||||
			else if(tokens[0].find("open") != std::string::npos)
 | 
			
		||||
			{
 | 
			
		||||
				if(tokens.size() > 1)
 | 
			
		||||
				{
 | 
			
		||||
					ret = -1;
 | 
			
		||||
					size_t index = std::stoul(tokens[1]);
 | 
			
		||||
					if(index < Camera::getAvailableCameras().size())
 | 
			
		||||
					{
 | 
			
		||||
						camera.openCamera(index);
 | 
			
		||||
						if(camera.isOpen())
 | 
			
		||||
						{
 | 
			
		||||
							ret = 0;
 | 
			
		||||
							camera.setAcquisitionMode(Camera::MODE_SINGLE);
 | 
			
		||||
							camera.setBayerMode(Camera::BAYER_GREEN);
 | 
			
		||||
							camera.setTriggerMode(Camera::TRIGGER_SOFTWARE);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					else 
 | 
			
		||||
					{
 | 
			
		||||
						std::cout<<"Index out of range\n";
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else if(tokens[0].find("capture") != std::string::npos)
 | 
			
		||||
			{
 | 
			
		||||
				if(tokens.size() > 1)
 | 
			
		||||
				{
 | 
			
		||||
					ret = -1;
 | 
			
		||||
					if(camera.isOpen())
 | 
			
		||||
					{
 | 
			
		||||
						filename = tokens[1] + ".png";
 | 
			
		||||
						camera.startAcquisition();
 | 
			
		||||
						camera.trigger();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		std::cout<<(ret == 0 ? "SUCESS\n" : "FAILURE\n");
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										453
									
								
								uvoscam.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										453
									
								
								uvoscam.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,453 @@
 | 
			
		|||
/**
 | 
			
		||||
* uvoscam
 | 
			
		||||
* Copyright (C) 2021 Carl Klemm
 | 
			
		||||
*
 | 
			
		||||
* This program is free software; you can redistribute it and/or
 | 
			
		||||
* modify it under the terms of the GNU General Public License
 | 
			
		||||
* version 3 as published by the Free Software Foundation.
 | 
			
		||||
*
 | 
			
		||||
* This program 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 this program; if not, write to the
 | 
			
		||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 | 
			
		||||
* Boston, MA  02110-1301, USA.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "uvoscam.h"
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <opencv2/imgproc.hpp>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include"log.h"
 | 
			
		||||
 | 
			
		||||
using namespace cam;
 | 
			
		||||
 | 
			
		||||
cv::Mat Camera::debayer(ArvBuffer *buffer)
 | 
			
		||||
{
 | 
			
		||||
	size_t bufferSize;
 | 
			
		||||
	const void* data =  arv_buffer_get_data(buffer, &bufferSize);
 | 
			
		||||
	const cv::Mat cvBuffer(static_cast<int>(height_), static_cast<int>(width_), CV_8U, const_cast<void*>(data), bufferSize/width_);
 | 
			
		||||
	cv::Mat cvResult;
 | 
			
		||||
	if(bayerMode == BAYER_DEBAYER)
 | 
			
		||||
	{
 | 
			
		||||
		cv::cvtColor(cvBuffer, cvResult,  cv::COLOR_BayerBG2BGR);
 | 
			
		||||
	}
 | 
			
		||||
	else if(bayerMode == BAYER_RED || bayerMode == BAYER_BLUE)
 | 
			
		||||
	{
 | 
			
		||||
		cvBuffer.copyTo(cvResult);
 | 
			
		||||
		for(int y = 0; y < cvResult.rows; y+=2)
 | 
			
		||||
		{
 | 
			
		||||
			uint8_t* colH = cvResult.ptr<uint8_t>(y);
 | 
			
		||||
			uint8_t* colL = cvResult.ptr<uint8_t>(y+1);
 | 
			
		||||
			for(int x = 0; x < cvResult.cols; x+=2)
 | 
			
		||||
			{
 | 
			
		||||
				if(bayerMode == BAYER_BLUE)
 | 
			
		||||
				{
 | 
			
		||||
					colH[x+1] = colH[x];
 | 
			
		||||
					colL[x]   = colH[x];
 | 
			
		||||
					colL[x+1] = colH[x];
 | 
			
		||||
				} else
 | 
			
		||||
				{
 | 
			
		||||
					colH[x]   = colL[x+1];
 | 
			
		||||
					colH[x+1] = colL[x+1];
 | 
			
		||||
					colL[x]   = colL[x+1];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if(bayerMode == BAYER_GREEN)
 | 
			
		||||
	{
 | 
			
		||||
		cvBuffer.copyTo(cvResult);
 | 
			
		||||
		for(int y = 0; y < cvResult.rows; ++y)
 | 
			
		||||
		{
 | 
			
		||||
			uint8_t* col = cvResult.ptr<uint8_t>(y);
 | 
			
		||||
			for(int x = 0; x < cvResult.cols; x+=2)
 | 
			
		||||
 				col[x+(y & 1)] = col[x+!(y & 1)];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return cvResult;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cv::Mat Camera::pack8(ArvBuffer *buffer, bool color)
 | 
			
		||||
{
 | 
			
		||||
	size_t bufferSize;
 | 
			
		||||
	const void* data =  arv_buffer_get_data(buffer, &bufferSize);
 | 
			
		||||
	Log(Log::DEBUG)<<"bufferSize "<<bufferSize;
 | 
			
		||||
	const cv::Mat cvBuffer(static_cast<int>(height_), static_cast<int>(width_), color ? CV_8UC3 : CV_8U, 
 | 
			
		||||
						   const_cast<void*>(data));
 | 
			
		||||
	cv::Mat cvResult;
 | 
			
		||||
	cvBuffer.copyTo(cvResult);
 | 
			
		||||
	return cvResult;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cv::Mat Camera::pack16(ArvBuffer *buffer)
 | 
			
		||||
{
 | 
			
		||||
	/*size_t bufferSize;
 | 
			
		||||
	void* data =  arv_buffer_get_data(buffer, &bufferSize);
 | 
			
		||||
	cv::Mat cvBuffer(static_cast<int>(height_), static_cast<int>(width_), color ? CV_8SC3 : CV_8SC1, data, bufferSize/width_);*/
 | 
			
		||||
	cv::Mat cvResult;
 | 
			
		||||
	//cvBuffer.copyTo(cvResult);
 | 
			
		||||
	return cvResult;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Camera::decoderThreadFunc()
 | 
			
		||||
{
 | 
			
		||||
	while(true)
 | 
			
		||||
	{
 | 
			
		||||
		std::unique_lock<std::mutex> bufferConditionMutexLock(bufferConditionMutex);
 | 
			
		||||
		bufferCondition.wait(bufferConditionMutexLock);
 | 
			
		||||
		if(join)
 | 
			
		||||
			return;
 | 
			
		||||
		decodeBufferMutex.lock();
 | 
			
		||||
		if(decodeBuffer != nullptr)
 | 
			
		||||
		{
 | 
			
		||||
			Log(Log::DEBUG)<<"decoderThreadFunc";
 | 
			
		||||
			if(format == ARV_PIXEL_FORMAT_BAYER_BG_8)
 | 
			
		||||
			{
 | 
			
		||||
				if(bayerMode != BAYER_PASSTHOUGH)
 | 
			
		||||
					callback_(debayer(decodeBuffer));
 | 
			
		||||
				else
 | 
			
		||||
					callback_(pack8(decodeBuffer, false));
 | 
			
		||||
			}
 | 
			
		||||
			else if(format == ARV_PIXEL_FORMAT_MONO_8)
 | 
			
		||||
			{
 | 
			
		||||
				callback_(pack8(decodeBuffer, false));
 | 
			
		||||
			}
 | 
			
		||||
			arv_stream_push_buffer(aStream_, decodeBuffer);
 | 
			
		||||
		}
 | 
			
		||||
		decodeBufferMutex.unlock();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Camera::aCallback(void* instance, ArvStreamCallbackType type, ArvBuffer *buffer)
 | 
			
		||||
{
 | 
			
		||||
	Camera* instance_ = reinterpret_cast<Camera*>(instance);
 | 
			
		||||
	if(type == ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE)
 | 
			
		||||
	{
 | 
			
		||||
		if(instance_->run)
 | 
			
		||||
		{
 | 
			
		||||
			gint inBuffers;
 | 
			
		||||
			gint outBuffers;
 | 
			
		||||
			arv_stream_get_n_buffers(instance_->aStream_, &inBuffers, &outBuffers);
 | 
			
		||||
			Log(Log::DEBUG)<<"ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE in "<<inBuffers<<" out "<<outBuffers;
 | 
			
		||||
			std::unique_lock<std::mutex> decodeBufferMutexLock(instance_->decodeBufferMutex);
 | 
			
		||||
			instance_->decodeBuffer = arv_stream_pop_buffer(instance_->aStream_);
 | 
			
		||||
			instance_->bufferCondition.notify_all();
 | 
			
		||||
			if(instance_->aqmode == MODE_SINGLE)
 | 
			
		||||
				instance_->run = false;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			arv_stream_push_buffer(instance_->aStream_, arv_stream_pop_buffer(instance_->aStream_));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Camera::getSize(unsigned int* width, unsigned int* height)
 | 
			
		||||
{
 | 
			
		||||
	*width = width_;
 | 
			
		||||
	*height = height_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::chooseFormat()
 | 
			
		||||
{
 | 
			
		||||
	guint count = 0;
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	gint64* formats = arv_camera_dup_available_pixel_formats(aCamera_, &count, &error);
 | 
			
		||||
	if(error)
 | 
			
		||||
		return false;
 | 
			
		||||
	for(guint i = 0; i < count && format < 0; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		switch(formats[i])
 | 
			
		||||
		{
 | 
			
		||||
			case ARV_PIXEL_FORMAT_MONO_8:
 | 
			
		||||
			case ARV_PIXEL_FORMAT_MONO_10:
 | 
			
		||||
			case ARV_PIXEL_FORMAT_MONO_12:
 | 
			
		||||
			case ARV_PIXEL_FORMAT_RGB_8_PLANAR:
 | 
			
		||||
			case ARV_PIXEL_FORMAT_BAYER_BG_8:
 | 
			
		||||
				format = formats[i];
 | 
			
		||||
			default:
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	arv_camera_set_pixel_format(aCamera_, format, &error);
 | 
			
		||||
	if(error)
 | 
			
		||||
		return false;
 | 
			
		||||
	
 | 
			
		||||
	return format >= 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::setupCamera()
 | 
			
		||||
{
 | 
			
		||||
	if(!chooseFormat())
 | 
			
		||||
	{
 | 
			
		||||
		Log(Log::ERROR)<<"Camera provides no supported pixel format";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	gint ymin, ymax;
 | 
			
		||||
	arv_camera_get_height_bounds(aCamera_, &ymin, &ymax, &error);
 | 
			
		||||
	if(error)
 | 
			
		||||
	{
 | 
			
		||||
		Log(Log::ERROR)<<"Can not get hight bounds";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	Log(Log::DEBUG)<<"Height bounds min: "<<ymin<<" max: "<<ymax;
 | 
			
		||||
	
 | 
			
		||||
	gint xmin, xmax;
 | 
			
		||||
	arv_camera_get_width_bounds(aCamera_, &xmin, &xmax, &error);
 | 
			
		||||
	if(error)
 | 
			
		||||
	{
 | 
			
		||||
		Log(Log::ERROR)<<"Can not get width bounds";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	Log(Log::DEBUG)<<"Width bounds min: "<<xmin<<" max: "<<xmax;
 | 
			
		||||
 | 
			
		||||
	arv_camera_set_region(aCamera_, 0, 0, xmax, ymax, nullptr);
 | 
			
		||||
 | 
			
		||||
	gint x, y, w, h;
 | 
			
		||||
	arv_camera_get_region(aCamera_, &x, &y, &w, &h, &error);
 | 
			
		||||
	if(error)
 | 
			
		||||
	{
 | 
			
		||||
		Log(Log::ERROR)<<"Can not get camera roi";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	width_ = w;
 | 
			
		||||
	height_= h;
 | 
			
		||||
	
 | 
			
		||||
	Log(Log::DEBUG)<<"Wdith "<<width_<<" Heigt "<<height_;
 | 
			
		||||
 | 
			
		||||
	bool binning = arv_camera_is_binning_available(aCamera_, &error);
 | 
			
		||||
	if(error)
 | 
			
		||||
	{
 | 
			
		||||
		Log(Log::ERROR)<<"Can not get camera binning";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if(binning)
 | 
			
		||||
	{
 | 
			
		||||
		arv_camera_set_binning(aCamera_, 1, 1, &error);
 | 
			
		||||
		if(error)
 | 
			
		||||
		{
 | 
			
		||||
			Log(Log::ERROR)<<"failed to set binning";
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	Log(Log::DEBUG)<<"Binning: "<<(binning ? "yes" : "no");
 | 
			
		||||
	
 | 
			
		||||
	decoderThread = new std::thread([this](){decoderThreadFunc();});
 | 
			
		||||
	
 | 
			
		||||
	Log(Log::DEBUG)<<"Using "<<arv_camera_get_pixel_format_as_string(aCamera_, nullptr)<<" as pixel format";
 | 
			
		||||
	
 | 
			
		||||
	aStream_ = arv_camera_create_stream(aCamera_, aCallback, this, nullptr);
 | 
			
		||||
	if(!ARV_IS_STREAM(aStream_))
 | 
			
		||||
	{
 | 
			
		||||
		Log(Log::ERROR)<<"Can not create stream";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	size_t frameSize = arv_camera_get_payload(aCamera_, nullptr);
 | 
			
		||||
	for(size_t i = 0; i < BUFFER_DEPTH; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		imageBuffers[i] = arv_buffer_new(frameSize, nullptr);
 | 
			
		||||
		arv_stream_push_buffer(aStream_, imageBuffers[i]);
 | 
			
		||||
	}
 | 
			
		||||
	setExposureAuto(false);
 | 
			
		||||
	setTriggerMode(TRIGGER_FREE);
 | 
			
		||||
	setAcquisitionMode(ARV_ACQUISITION_MODE_CONTINUOUS);
 | 
			
		||||
	setFrameRate(10);
 | 
			
		||||
	setExposureTime(100000);
 | 
			
		||||
	arv_camera_stop_acquisition(aCamera_, nullptr);
 | 
			
		||||
	
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<Camera::Description> Camera::getAvailableCameras(bool update)
 | 
			
		||||
{
 | 
			
		||||
	if(!scanned_ || update)
 | 
			
		||||
	{
 | 
			
		||||
		arv_update_device_list();
 | 
			
		||||
		scanned_ = true;
 | 
			
		||||
	}
 | 
			
		||||
	std::vector<Description> cameras;
 | 
			
		||||
	for(size_t i = 0; i < arv_get_n_devices(); ++i)
 | 
			
		||||
	{
 | 
			
		||||
		Description camera;
 | 
			
		||||
		camera.vendor = arv_get_device_vendor(i);
 | 
			
		||||
		camera.serial = arv_get_device_serial_nbr(i);
 | 
			
		||||
		camera.id     = arv_get_device_id(i);
 | 
			
		||||
		camera.model  = arv_get_device_model(i);
 | 
			
		||||
		cameras.push_back(camera);
 | 
			
		||||
	}
 | 
			
		||||
	return cameras;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Camera::Camera(std::function<void(cv::Mat)> callback): join(false), run(false), callback_(callback)
 | 
			
		||||
{
 | 
			
		||||
	arv_enable_interface("Fake");
 | 
			
		||||
}
 | 
			
		||||
	
 | 
			
		||||
bool Camera::openCamera(const std::string& name)
 | 
			
		||||
{
 | 
			
		||||
	aCamera_ = arv_camera_new(name.c_str(), nullptr);
 | 
			
		||||
	if(ARV_IS_CAMERA(aCamera_))
 | 
			
		||||
		setupCamera();
 | 
			
		||||
	else
 | 
			
		||||
		Log(Log::ERROR)<<"Can not create camera from name "<<name;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::openCamera(const Camera::Description& camera)
 | 
			
		||||
{
 | 
			
		||||
	aCamera_ = arv_camera_new(camera.id.c_str(), nullptr);
 | 
			
		||||
	if(ARV_IS_CAMERA(aCamera_))
 | 
			
		||||
		setupCamera();
 | 
			
		||||
	else
 | 
			
		||||
		Log(Log::ERROR)<<"Can not create camera";
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::openCamera(const size_t index)
 | 
			
		||||
{
 | 
			
		||||
	Description camera = getAvailableCameras().at(index);
 | 
			
		||||
	aCamera_ = arv_camera_new(camera.id.c_str(), nullptr);
 | 
			
		||||
	if(ARV_IS_CAMERA(aCamera_))
 | 
			
		||||
		setupCamera();
 | 
			
		||||
	else
 | 
			
		||||
		Log(Log::ERROR)<<"Can not create camera from index "<<index<<" name "<<camera.model;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Camera::~Camera()
 | 
			
		||||
{
 | 
			
		||||
	join = true;
 | 
			
		||||
	if(decoderThread)
 | 
			
		||||
	{
 | 
			
		||||
		bufferCondition.notify_all();
 | 
			
		||||
		decoderThread->join();
 | 
			
		||||
	}
 | 
			
		||||
	if(ARV_IS_STREAM(aStream_))
 | 
			
		||||
	{
 | 
			
		||||
		stopAcquisition();
 | 
			
		||||
		g_object_unref(aStream_);
 | 
			
		||||
	}
 | 
			
		||||
	if(ARV_IS_CAMERA(aCamera_))
 | 
			
		||||
		g_object_unref(aCamera_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::isOpen()
 | 
			
		||||
{
 | 
			
		||||
	return ARV_IS_STREAM(aStream_) && ARV_IS_CAMERA(aCamera_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::setAcquisitionMode(AquisitionMode mode)
 | 
			
		||||
{
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	aqmode = mode;
 | 
			
		||||
	arv_camera_set_acquisition_mode(aCamera_, mode == MODE_FREE ? 
 | 
			
		||||
	                                ARV_ACQUISITION_MODE_CONTINUOUS : ARV_ACQUISITION_MODE_SINGLE_FRAME, &error);
 | 
			
		||||
	return !error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::setExposureTime(uint64_t us)
 | 
			
		||||
{
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	arv_camera_set_exposure_time(aCamera_, static_cast<double>(us), &error);
 | 
			
		||||
	return !error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t Camera::getExposureTime()
 | 
			
		||||
{
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	double ret = arv_camera_get_exposure_time(aCamera_, &error);
 | 
			
		||||
	return !error ? static_cast<uint64_t>(ret) : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double Camera::getFrameRate()
 | 
			
		||||
{
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	double ret = arv_camera_get_frame_rate(aCamera_, &error);
 | 
			
		||||
	return !error ? ret : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::setFrameRate(double rate)
 | 
			
		||||
{
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	arv_camera_set_frame_rate(aCamera_, rate, &error);
 | 
			
		||||
	return !error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t Camera::getPixelFormat()
 | 
			
		||||
{
 | 
			
		||||
	return static_cast<ArvPixelFormat>(format);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::setExposureAuto(bool enable)
 | 
			
		||||
{
 | 
			
		||||
	if(!arv_camera_is_exposure_auto_available(aCamera_, nullptr))
 | 
			
		||||
		return false;
 | 
			
		||||
	
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	arv_camera_set_exposure_time(aCamera_, enable ? ARV_AUTO_CONTINUOUS : ARV_AUTO_OFF, &error);
 | 
			
		||||
	return !error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::startAcquisition()
 | 
			
		||||
{
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	arv_camera_start_acquisition(aCamera_, &error);
 | 
			
		||||
	if(!error)
 | 
			
		||||
		run = true;
 | 
			
		||||
	return !error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Camera::stopAcquisition()
 | 
			
		||||
{
 | 
			
		||||
	GError* error = nullptr;
 | 
			
		||||
	arv_camera_stop_acquisition(aCamera_, &error);
 | 
			
		||||
	if(!error)
 | 
			
		||||
		run = false;
 | 
			
		||||
	return !error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Camera::setBayerMode(Camera::BayerMode mode)
 | 
			
		||||
{
 | 
			
		||||
	bayerMode = mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Camera::BayerMode Camera::getBayerMode()
 | 
			
		||||
{
 | 
			
		||||
	return bayerMode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Camera::setTriggerMode(Camera::TriggerMode mode)
 | 
			
		||||
{
 | 
			
		||||
	switch(mode)
 | 
			
		||||
	{
 | 
			
		||||
		case TRIGGER_FREE:
 | 
			
		||||
			arv_camera_clear_triggers(aCamera_, nullptr);
 | 
			
		||||
			break;
 | 
			
		||||
		case TRIGGER_SOFTWARE:
 | 
			
		||||
			arv_camera_set_trigger(aCamera_, "Software", nullptr);
 | 
			
		||||
			break;
 | 
			
		||||
		case TRIGGER_HARDWARE:
 | 
			
		||||
			arv_camera_set_trigger(aCamera_, "Line1", nullptr);
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Camera::trigger()
 | 
			
		||||
{
 | 
			
		||||
	arv_camera_software_trigger(aCamera_, nullptr);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										129
									
								
								uvoscam.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								uvoscam.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,129 @@
 | 
			
		|||
/**
 | 
			
		||||
* uvoscam
 | 
			
		||||
* Copyright (C) 2021 Carl Klemm
 | 
			
		||||
*
 | 
			
		||||
* This program is free software; you can redistribute it and/or
 | 
			
		||||
* modify it under the terms of the GNU General Public License
 | 
			
		||||
* version 3 as published by the Free Software Foundation.
 | 
			
		||||
*
 | 
			
		||||
* This program 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 this program; if not, write to the
 | 
			
		||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 | 
			
		||||
* Boston, MA  02110-1301, USA.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <opencv2/core/mat.hpp>
 | 
			
		||||
#include <arv.h>
 | 
			
		||||
 | 
			
		||||
namespace cam
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
class Camera
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	
 | 
			
		||||
	struct Description
 | 
			
		||||
	{
 | 
			
		||||
		std::string vendor;
 | 
			
		||||
		std::string serial;
 | 
			
		||||
		std::string id;
 | 
			
		||||
		std::string model;
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	static constexpr size_t BUFFER_DEPTH = 8;
 | 
			
		||||
	
 | 
			
		||||
	typedef int TriggerMode;
 | 
			
		||||
	static constexpr TriggerMode TRIGGER_FREE     = 0;
 | 
			
		||||
	static constexpr TriggerMode TRIGGER_SOFTWARE = 1;
 | 
			
		||||
	static constexpr TriggerMode TRIGGER_HARDWARE = 2;
 | 
			
		||||
	
 | 
			
		||||
	typedef int BayerMode;
 | 
			
		||||
	static constexpr BayerMode BAYER_RED        = 0;
 | 
			
		||||
	static constexpr BayerMode BAYER_GREEN      = 1;
 | 
			
		||||
	static constexpr BayerMode BAYER_BLUE       = 2;
 | 
			
		||||
	static constexpr BayerMode BAYER_PASSTHOUGH = 3;
 | 
			
		||||
	static constexpr BayerMode BAYER_DEBAYER    = 4;
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	typedef int AquisitionMode;
 | 
			
		||||
	static constexpr AquisitionMode MODE_FREE   = 0;
 | 
			
		||||
	static constexpr AquisitionMode MODE_SINGLE = 1;
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	ArvStream* aStream_ = nullptr;
 | 
			
		||||
	ArvCamera* aCamera_ = nullptr;
 | 
			
		||||
	ArvInterface interface;
 | 
			
		||||
	
 | 
			
		||||
	unsigned int width_;
 | 
			
		||||
	unsigned int height_;
 | 
			
		||||
	int64_t format = -1;
 | 
			
		||||
	inline static bool scanned_ = false;
 | 
			
		||||
	
 | 
			
		||||
	ArvBuffer* imageBuffers[BUFFER_DEPTH] = {0};
 | 
			
		||||
	
 | 
			
		||||
	BayerMode bayerMode = BAYER_DEBAYER;
 | 
			
		||||
	
 | 
			
		||||
	ArvBuffer* decodeBuffer = nullptr;
 | 
			
		||||
	std::mutex decodeBufferMutex;
 | 
			
		||||
	std::condition_variable bufferCondition;
 | 
			
		||||
	std::mutex bufferConditionMutex;
 | 
			
		||||
	std::thread* decoderThread = nullptr;
 | 
			
		||||
	std::atomic_bool join;
 | 
			
		||||
	
 | 
			
		||||
	std::atomic_bool run;
 | 
			
		||||
	
 | 
			
		||||
	AquisitionMode aqmode = MODE_FREE;
 | 
			
		||||
	
 | 
			
		||||
	static void aCallback(void* instance, ArvStreamCallbackType type, ArvBuffer *buffer);
 | 
			
		||||
	
 | 
			
		||||
	void decoderThreadFunc();
 | 
			
		||||
	
 | 
			
		||||
	std::function<void(cv::Mat)> callback_;
 | 
			
		||||
	
 | 
			
		||||
	bool setupCamera();
 | 
			
		||||
	
 | 
			
		||||
	bool chooseFormat();
 | 
			
		||||
	
 | 
			
		||||
	cv::Mat debayer(ArvBuffer *buffer);
 | 
			
		||||
	cv::Mat pack8(ArvBuffer *buffer, bool color);
 | 
			
		||||
	cv::Mat pack16(ArvBuffer *buffer);
 | 
			
		||||
	
 | 
			
		||||
public:
 | 
			
		||||
	
 | 
			
		||||
	static std::vector<Camera::Description> getAvailableCameras(bool update = false);
 | 
			
		||||
	
 | 
			
		||||
	Camera(std::function<void(cv::Mat)> callback);
 | 
			
		||||
	bool openCamera(const std::string& name);
 | 
			
		||||
	bool openCamera(const Camera::Description& camera);
 | 
			
		||||
	bool openCamera(const size_t index);
 | 
			
		||||
	~Camera();
 | 
			
		||||
	bool isOpen();
 | 
			
		||||
	bool setAcquisitionMode(AquisitionMode mode);
 | 
			
		||||
	bool setExposureTime(uint64_t us);
 | 
			
		||||
	uint64_t getExposureTime();
 | 
			
		||||
	double getFrameRate();
 | 
			
		||||
	bool setFrameRate(double rate);
 | 
			
		||||
	int64_t getPixelFormat();
 | 
			
		||||
	bool setExposureAuto(bool enable);
 | 
			
		||||
	bool startAcquisition();
 | 
			
		||||
	bool stopAcquisition();
 | 
			
		||||
	void getSize(unsigned int* x, unsigned int* y);
 | 
			
		||||
	void setBayerMode(Camera::BayerMode mode);
 | 
			
		||||
	Camera::BayerMode getBayerMode();
 | 
			
		||||
	void setTriggerMode(Camera::TriggerMode mode);
 | 
			
		||||
	void trigger();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue