Xavier红外相机(IP摄像头)开发记录
1.相机基本信息
相机分辨率 640×512, 成像数据横向扫描,以16进制数据保存,每个像素按照16 bit存储,高两bit无效,为0,14 bit为有效数据。一帧图像文件大小为640×512×2 byte。使用摄像头需要网线连接相机端与主机端,并固定主机IP地址192.168.1.xxx
,相机IP地址为192.168.1.201
。
2.数据采集程序
采集的图像数据存储在变量buffer中,为16进制数据,需要解码显示
修改Makefile中的平台编译器
# 修改编译平台
CC = aarch64-linux-gnu-gcc
CPP = aarch64-linux-gnu-g++
# 添加参数 -fPIC
linux-release:
$(MAKE) all -lpthread CFLAGS="-Wall -DNDEBUG -O2" CPPFLAGS="-Wall -DNDEBUG -O2 -DBSD=1 -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -fPIC"
编译命令
# 选择编译版本
make linux-release
# 链接
g++ CamManager.o Clinet_API.o main.o NetSocket.o TirNetInterface.o -o main
# 运行
./main
输出
相机链接成功,接收100帧数据
以下为使用UltraEdit软件下查看一帧数据保存的内容,为16进制数据。
3.红外图像转码程序 16bit → \rightarrow → 8bit
归一化阈值方案
8-bit像素值8pix
16-bit像素值16pix
normal_threshold为1200
8pix =(16pix / normal_threshold)
×
\times
× 255.0
归一化阈值当出现异常高温区域时画面会出现黑洞,可能是像素值太大表示不出
线性映射方案 + CLAHE
首先遍历获取图像最大值max与最小值min
线性映射公式:
8pix = (16pix - min)
×
\times
× 255.0/(max - min)
8pix:8-bit像素值;16pix:16-bit像素值
通过以上公式直接转换,对于不同场景,亮度-灰度变化太大
利用对比度受限自适应直方图均衡化算法增强,以减少亮度-灰度变化
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
int main(int argc, char** argv){
///参数
short *data_buffer = new short[640*512]; //文件缓存
std::string file_path = "/home/siu/"; //文件路径
float normal_threshold = 1000.0; //显示的归一化阈值
///数据读取
std::ifstream inF(file_path+"file.txt", std::ios::binary);
inF.read((char *)data_buffer, sizeof(short) * (640*512));
inF.close();
while (1)
{
cv::Mat show_mat(512, 640, CV_8UC1, cv::Scalar::all(0));
cv::Mat dst_mat(512, 640, CV_8UC1, cv::Scalar::all(0));
// 寻找16bit图像最大、最小值
float min = data_buffer[0], max=data_buffer[0];
for (int r = 0; r < show_mat.rows; r++)
{
for (int c = 0; c < show_mat.cols; c++)
{
float pix = data_buffer[(r * 640) + c];
if(pix > max)max = pix;
if(pix < min)min = pix;
}
}
cout<< max <<"\n"<< min <<endl;
//填充mat
for (int x = 0; x < show_mat.rows; x++)
{
char *grayRow = show_mat.ptr<char>(x);
for (int y = 0; y < show_mat.cols; y++)
{
float pix = data_buffer[(x * 640) + y];
// grayRow[y] = ((pix / normal_threshold) * 255.0); // 归一化阈值显示方案
grayRow[y] = ((pix - min)/(max - min))*255.0; // 线性映射
}
}
// CLAHE 对比度受限自适应直方图均衡化
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();
clahe->setClipLimit(4);
clahe->apply(show_mat, dst_mat);
std::cout << "normal_threshold : " << normal_threshold << std::endl;
cv::imshow("image", dst_mat);
cv::waitKey(0);
}
return 0;
}
编写CMakeLists.txt
# cmake needs this line
cmake_minimum_required(VERSION 3.20.2)
# Define project name
project(img-decode)
set(CMAKE_CXX_FLAGS "-std=c++11")
# Find OpenCV, you may need to set OpenCV_DIR variable
# to the absolute path to the directory containing OpenCVConfig.cmake file
# via the command line or GUI
find_package(OpenCV REQUIRED)
# If the package has been found, several variables will
# be set, you can find the full list with descriptions
# in the OpenCVConfig.cmake file.
# Print some message showing some of them
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
# Add OpenCV headers location to your include paths
include_directories(${OpenCV_INCLUDE_DIRS})
# Declare the executable target built from your sources
add_executable(decode yours_ir.cpp)
# Link your application with OpenCV libraries
target_link_libraries(decode ${OpenCV_LIBS})
编译,进入代码文件夹执行以下编译命令
mkdir build && cd build
cmake ..
make
# 运行
./decode
转码图像显示效果
归一化阈值显示效果
线性映射显示效果
4.红外图像采集程序
将红外转码程序写入数据获取程序中,实时转码显示,利用opencv显示
Makefile需要添加opencv库,修改Makefile
INCLUDES = -I/usr/local/include/opencv
LIBS = -lpthread -fPIC
LIBS += -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml
编译完,链接时也需要链接opencv,否则出现undefined renference
错误
g++ xx.o -o main $(pkg-config --cflags --libs opencv)
编译命令
make linux-release
g++ CamManager.o Clinet_API.o main.o NetSocket.o TirNetInterface.o -o main $(pkg-config --cflags --libs opencv4)
# 运行
./main
5.使用ROS发布采集的红外图像流
1.创建ROS工作空间
mkdir -p ~/test_ws/src
cd ~/test_ws/src
cd ..
catkin init
cd src
2.创建ROS功能包
catkin_create_pkg ir_cam sensor_msgs cv_bridge roscpp std_msgs image_transport
cd ..
catkin_make
source ./devel/setup.bash
将.h文件放入include/ir_cam/
,将.cpp文件放入src/
,修改.cpp中包含的头文件,如将#include "Clinet_API.h"
改为 #include "ir_cam/Clinet_API.h"
3.编写ROS发布程序
在main.cpp中编写ros发布程序,可参考博客编写
4.创建launch文件夹,编写launch文件,在文件中编写以下内容
<launch>
<node name="ir_cam" pkg="ir_cam" type="ir_cam" output="screen" />
</launch>
5.编写CmakeList.txt文件
编写以下内容
find_package(catkin REQUIRED COMPONENTS
cv_bridge
image_transport
roscpp
sensor_msgs
std_msgs
)
# opencv根据自己的路径修改
set(OpenCV_DIR /usr/include/opencv4)
find_package(OpenCV REQUIRED)
# 打印找到的opencv库信息
# If the package has been found, several variables will
# be set, you can find the full list with descriptions
# in the OpenCVConfig.cmake file.
# Print some message showing some of them
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
include_directories(
include
${catkin_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
)
# 生成并链接第三方库,这一步会生成.so文件 libir_cam_lib.so
file(GLOB INC_DIR include/ir_cam/*.h) # 所有的.h文件
file(GLOB CPP_DIR src/*.cpp) # 所有的.cpp文件
add_library(${PROJECT_NAME}_LIB SHARED ${CPP_DIR} ${INC_DIR})
link_libraries(${PROJECT_NAME}_LIB)
# 生成可执行文件
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME}
${PROJECT_NAME}_LIB
${OpenCV_LIBS}
${catkin_LIBRARIES}
)
6.编译运行
切换到test_ws路径下执行
catkin_make
编译成功
终端运行
roslaunch ir_cam ir_cam.launch
7.使用rviz查看发布的数据
rosrun rviz rviz
8.使用第三方库解码红外图像
静态链接库ImgProc.a
与ImgProc.h
头文件
将ImgProc.h
放入include
文件夹,在include
同级目录创建lib
文件夹,将静态链接库名称修改为libImgProc.a放入其中。
main.cpp
添加头文件#include "ir_cam/ImgProc.h"
,加入解码码代码处理获取的数据buffer
,解码数据为imgDst
ImgPara imgSrc, imgDst;
// imgSrc.nWidth = m_imageW;
// imgSrc.nHeight = m_imageH;
imgSrc.nWidth = 640;
imgSrc.nHeight = 512;
imgSrc.wBpps = 14;
imgSrc.wChannel = 1;
//imgSrc.pData = (void*)m_rawData.c_str();
imgSrc.pData = (void *)buffer;
char pData[640*512];
// imgDst.nWidth = m_imageW;
// imgDst.nHeight = m_imageH;
imgDst.nWidth = 640;
imgDst.nHeight = 512;
imgDst.wBpps = 8;
imgDst.wChannel = 1;
imgDst.pData = (void *)pData;
Change14bitTO8bit(&imgSrc, &imgDst, FALSE, FALSE);
在CmakeList.txt中添加第三方静态库引用
find_library(LIB libImgProc.a)
# 若出现 NOT FOUND 添加绝对路径
# find_library(LIB libImgProc.a PATHS /path/绝对路径 )
link_directories(${LIB})
target_link_libraries(${PROJECT_NAME} ${LIB} libImgProc.a)
编译运行同上