fast/3rdparty/hikvision/rgbd_camera/inc/RenderWindow.hpp
2025-01-20 10:30:01 +08:00

1265 lines
40 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#define GLFW_INCLUDE_GLU
#include <GLFW/glfw3.h>
#include <map>
#include <cmath>
#include <vector>
#include <memory>
#include <iostream>
#include <algorithm>
#include <functional>
//注意请将glad.h和glad.c文件添加到工程中
//工程依赖opengl32.lib glu32.lib glfw3.lib
//请使用VS2013版本
namespace RenderImage
{
//像素格式
enum RIPixelType
{
RIPixelType_Undefined = 0xFFFFFFFF,
RIPixelType_Mono8 = 17301505,
RIPixelType_RGB8_Planar = 35127329,
RIPixelType_Coord3D_ABC32f = 39846080,
RIPixelType_Coord3D_C16 = 17825976,
RIPixelType_RGB8_Packed = 35127316,
RIPixelType_RGBD_C16 = 0x82283007,
};
enum ColorTableType
{
ColorTableHue,
ColorTableJet,
ColorTableClassic,
ColorTableGrayScale,
ColorTableBiomes,
ColorTableCold,
ColorTableWarm,
ColorTableQuant,
ColorTablePattern,
};
//图像信息
struct RIFrameInfo
{
unsigned char* pData; //图像数据
unsigned short nWidth; //宽度
unsigned short nHeight; //高度
unsigned int nFrameNum; //帧号
unsigned int nFrameLength; //数据长度
RIPixelType enPixelType; //像素格式
unsigned int nReserved[4]; //预留字节
};
//自动管理数据
typedef struct _AUTO_MALLOC_DATA_INFO_
{
_AUTO_MALLOC_DATA_INFO_()
: pData(nullptr)
, nDataLen(0)
, nDataBufferSize(0)
{}
~_AUTO_MALLOC_DATA_INFO_()
{
Release();
}
_AUTO_MALLOC_DATA_INFO_(const _AUTO_MALLOC_DATA_INFO_&) = delete;
_AUTO_MALLOC_DATA_INFO_& operator=(const _AUTO_MALLOC_DATA_INFO_&) = delete;
bool ResizeData(int nNewDataLen)
{
if (this->nDataBufferSize >= nNewDataLen)
{
ResetData();
return true;
}
Release();
this->pData = (unsigned char*)malloc(nNewDataLen);
if (this->pData)
{
this->nDataBufferSize = nNewDataLen;
}
ResetData();
return true;
}
void ResetData()
{
if (this->pData)
{
memset(this->pData, 0, this->nDataBufferSize);
}
}
void Release()
{
if (this->pData)
{
free(this->pData);
this->pData = nullptr;
this->nDataBufferSize = 0;
this->nDataLen = 0;
}
}
unsigned char* pData;
int nDataLen;
int nDataBufferSize;
}AUTO_MALLOC_DATA_INFO;
}
namespace RenderImage
{
class RenderTexture;
struct glfw_state;
class RenderImgWnd
{
public:
RenderImgWnd(int width, int height, const char* title);
~RenderImgWnd();
void CloseWnd();
//渲染2D图像Mono8、C16、RGB
void RenderImage(const RIFrameInfo& frame);
//配置数据范围
void SetPointCloudRange(float fMinX, float fMaxX, float fMinY, float fMaxY);
//渲染点云(仅支持RIPixelType_Coord3D_ABC32f格式)
void RenderPointCloud(const RIFrameInfo& frame);
//C16深度图显示伪彩色时的颜色表
void SetColorTable(ColorTableType enType);
//初始化点云渲染环境3D点云渲染之前调用一次
void Init3DRender();
operator bool();
private:
std::shared_ptr<RenderTexture> m_pTexture;
std::shared_ptr<glfw_state> m_pRenderState;
AUTO_MALLOC_DATA_INFO m_stPointCloudConvert;
GLFWwindow* win = nullptr;
int _width = 0;
int _height = 0;
ColorTableType m_enColorTable = ColorTableJet;
float m_fMinX = 0;
float m_fMaxX = 0;
float m_fMinY = 0;
float m_fMaxY = 0;
std::function<void(bool)> on_left_mouse = [](bool) {};
std::function<void(double, double)> on_mouse_scroll = [](double, double) {};
std::function<void(double, double)> on_mouse_move = [](double, double) {};
std::function<void(int)> on_key_release = [](int) {};
};
}
#define C16_INVALID_VALUE (-32768)
using namespace std;
namespace RenderImage
{
struct float2 { float x, y; };
struct rect
{
float x, y;
float w, h;
// Create new rect within original boundaries with give aspect ration
rect adjust_ratio(float2 size) const
{
auto H = static_cast<float>(h), W = static_cast<float>(h)* size.x / size.y;
if (W > w)
{
auto scale = w / W;
W *= scale;
H *= scale;
}
return{ x + (w - W) / 2, y + (h - H) / 2, W, H };
}
};
struct float3
{
float x, y, z;
float & operator[](int i)
{
return (*(&x + i));
}
};
inline float3 operator * (const float3 & a, float b) { return{ a.x*b, a.y*b, a.z*b }; }
inline float3 operator + (const float3 & a, const float3 & b) { return{ a.x + b.x, a.y + b.y, a.z + b.z }; }
template< typename T>
inline T clamp_val(T val, const T& min, const T& max)
{
const T t = val < min ? min : val;
return t > max ? max : t;
}
void set_viewport(const rect& r)
{
glViewport((int)r.x, (int)r.y, (int)r.w, (int)r.h);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glOrtho(0, r.w, r.h, 0, -1, +1);
}
// Struct for managing rotation of pointcloud view
struct glfw_state {
glfw_state(float yaw = 15.0, float pitch = 15.0) : yaw(yaw), pitch(pitch), last_x(0.0), last_y(0.0),
ml(false), offset_x(2.f), offset_y(2.f) {}
double yaw;
double pitch;
double last_x;
double last_y;
bool ml;
float offset_x;
float offset_y;
};
class ColorTable
{
public:
static ColorTable& GetColorTable(ColorTableType enType);
ColorTable(std::map<float, float3> map, int steps = 4000);
ColorTable(const std::vector<float3>& values, int steps = 4000);
ColorTable();
inline float3 get(float value) const
{
if (_max == _min) return *_data;
auto t = (value - _min) / (_max - _min);
t = clamp_val(t, 0.f, 1.f);
return _data[(int)(t * (_size - 1))];
}
float min_key() const { return _min; }
float max_key() const { return _max; }
const std::vector<float3>& get_cache() const { return _cache; }
private:
inline float3 lerp(const float3& a, const float3& b, float t) const
{
return b * t + a * (1 - t);
}
float3 calc(float value) const;
void initialize(int steps);
std::map<float, float3> _map;
std::vector<float3> _cache;
float _min, _max;
size_t _size; float3* _data;
};
////////////////////////
// Image display code //
////////////////////////
/// \brief The texture class
bool ConvertImageData(const RIFrameInfo& stSrcImageInfo, RIFrameInfo& stDstImageInfo, ColorTableType enColorTableType);
bool ConvertMono8_2_RGB(unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData);
bool ConvertC16_2_RGB( unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData, ColorTable& stColorTable);
bool ConvertRGB8P_2_RGB(unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData);
bool ConvertRGB_2_RGB( unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData);
bool ConvertRGB24D16_2_RGB(unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData);
bool NormalizeABC32f(unsigned char* pSrcData, int nDataLen, unsigned char* pDstData, float* fZRatio, float fMinX, float fMaxX, float fMinY, float fMaxY);
//RGBD渲染使用的颜色表
std::vector<float3> m_vecRGBDColorTable;
float g_fContrastEnhance = 0.0;
float g_fWeightedRatio = 0.5;
void InitColorTable()
{
if (!m_vecRGBDColorTable.empty())
{
return;
}
//构建灰度值到彩色的映射表,蓝色->红色
float3 color;
for (int i = 0; i < 256; ++i)
{
if (i >= 0 && i <= 63)
{
color.x = 0;
color.y = 4 * i + 2;
color.z = 255;
}
else if (i >= 64 && i <= 127)
{
color.x = 0;
color.y = 255;
color.z = 510 - 4 * i;
}
else if (i >= 128 && i <= 191)
{
color.x = 4 * i - 510;
color.y = 255;
color.z = 0;
}
else
{
color.x = 255;
color.y = 1022 - 4 * i;
color.z = 0;
}
m_vecRGBDColorTable.push_back(color);
}
}
class RenderTexture
{
public:
void upload(const RIFrameInfo& frame, ColorTableType enColorTableType)
{
if (!_gl_handle)
glGenTextures(1, &_gl_handle);
GLenum err = glGetError();
glBindTexture(GL_TEXTURE_2D, _gl_handle);
switch (frame.enPixelType)
{
case RIPixelType_RGB8_Packed:
case RIPixelType_RGB8_Planar:
case RIPixelType_Coord3D_C16:
case RIPixelType_Mono8:
case RIPixelType_RGBD_C16:
{
//转换为rgb图像显示
RIFrameInfo stConvertImage = frame;
if (!m_stConvertData.ResizeData((frame.nWidth + 3) * frame.nHeight * 3))
{
return;
}
stConvertImage.pData = m_stConvertData.pData;
stConvertImage.enPixelType = RIPixelType_RGB8_Packed;
if (ConvertImageData(frame, stConvertImage, enColorTableType))
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, stConvertImage.nWidth, stConvertImage.nHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, stConvertImage.pData);
}
}
break;
default:
break;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
void show(const rect& r, float alpha = 1.f) const
{
if (!_gl_handle)
return;
set_viewport(r);
glBindTexture(GL_TEXTURE_2D, _gl_handle);
glColor4f(1.0f, 1.0f, 1.0f, alpha);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(0, 1); glVertex2f(0, r.h);
glTexCoord2f(1, 1); glVertex2f(r.w, r.h);
glTexCoord2f(1, 0); glVertex2f(r.w, 0);
glEnd();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
GLuint get_gl_handle() { return _gl_handle; }
void render(const RIFrameInfo& frame, const rect& rect, ColorTableType enColorTableType, float alpha = 1.f)
{
upload(frame, enColorTableType);
show(rect.adjust_ratio({ (float)frame.nWidth, (float)frame.nHeight }), alpha);
}
private:
GLuint _gl_handle = 0;
int _stream_index{};
AUTO_MALLOC_DATA_INFO m_stConvertData;
};
RenderImgWnd::RenderImgWnd(int width, int height, const char* title)
: _width(width)
, _height(height)
{
glfwInit();
win = glfwCreateWindow(width, height, title, nullptr, nullptr);
if (!win)
throw std::runtime_error("Could not open OpenGL window, please check your graphic drivers or use the textual SDK tools");
glfwMakeContextCurrent(win);
glfwSetWindowUserPointer(win, this);
glfwSetMouseButtonCallback(win, [](GLFWwindow* w, int button, int action, int mods)
{
auto s = (RenderImgWnd*)glfwGetWindowUserPointer(w);
if (button == 0) s->on_left_mouse(action == GLFW_PRESS);
});
glfwSetScrollCallback(win, [](GLFWwindow* w, double xoffset, double yoffset)
{
auto s = (RenderImgWnd*)glfwGetWindowUserPointer(w);
s->on_mouse_scroll(xoffset, yoffset);
});
glfwSetCursorPosCallback(win, [](GLFWwindow* w, double x, double y)
{
auto s = (RenderImgWnd*)glfwGetWindowUserPointer(w);
s->on_mouse_move(x, y);
});
glfwSetKeyCallback(win, [](GLFWwindow* w, int key, int scancode, int action, int mods)
{
auto s = (RenderImgWnd*)glfwGetWindowUserPointer(w);
if (0 == action) // on key release
{
s->on_key_release(key);
}
});
}
RenderImgWnd::~RenderImgWnd()
{
glfwDestroyWindow(win);
glfwTerminate();
}
void RenderImgWnd::CloseWnd()
{
glfwSetWindowShouldClose(win, 1);
}
RenderImgWnd::operator bool()
{
glPopMatrix();
glfwSwapBuffers(win);
auto res = !glfwWindowShouldClose(win);
glfwPollEvents();
glfwGetFramebufferSize(win, &_width, &_height);
// Clear the framebuffer
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, _width, _height);
// Draw the images
glPushMatrix();
glfwGetWindowSize(win, &_width, &_height);
glOrtho(0, _width, _height, 0, -1, +1);
return res;
}
void RenderImgWnd::RenderImage(const RIFrameInfo& frame)
{
if (nullptr == m_pTexture)
{
m_pTexture = std::make_shared<RenderTexture>();
}
if (nullptr == m_pTexture)
{
return;
}
m_pTexture->render(frame, {0, 0, (float)_width, (float)_height}, m_enColorTable);
}
//配置数据范围
void RenderImgWnd::SetPointCloudRange(float fMinX, float fMaxX, float fMinY, float fMaxY)
{
m_fMinX = fMinX;
m_fMaxX = fMaxX;
m_fMinY = fMinY;
m_fMaxY = fMaxY;
}
void RenderImgWnd::RenderPointCloud(const RIFrameInfo& frame)
{
if (frame.enPixelType != RIPixelType_Coord3D_ABC32f)
{
return;
}
if (nullptr == m_pRenderState || frame.nWidth <= 0 || frame.nHeight <= 0)
{
return;
}
if (!m_stPointCloudConvert.ResizeData(frame.nFrameLength))
{
return;
}
float fZRatio = 1.0f;
NormalizeABC32f(frame.pData, frame.nFrameLength, m_stPointCloudConvert.pData, &fZRatio, m_fMinX, m_fMaxX, m_fMinY, m_fMaxY);
// OpenGL commands that prep screen for the pointcloud
glLoadIdentity();
glPushAttrib(GL_ALL_ATTRIB_BITS);
glClearColor(153.f / 255, 153.f / 255, 153.f / 255, 1);
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluPerspective(60, _width / _height, 0.01f, 10.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
gluLookAt(0, 0, 0, 0, 0, 1, 0, -1, 0);
glTranslatef(0, 0, +2.2f + m_pRenderState->offset_y * 0.05f);
glRotated(m_pRenderState->pitch, 1, 0, 0);
glRotated(m_pRenderState->yaw, 0, 1, 0);
glTranslatef(0, 0, -0.5f);
glPointSize(1.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
//glBindTexture(GL_TEXTURE_2D, app_state.tex.get_gl_handle());
float tex_border_color[] = { 0.8f, 0.8f, 0.8f, 0.8f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, tex_border_color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 0x812F); // GL_CLAMP_TO_EDGE
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 0x812F); // GL_CLAMP_TO_EDGE
glBegin(GL_POINTS);
/* this segment actually prints the pointcloud */
//auto vertices = points.get_vertices(); // get vertices
//auto tex_coords = points.get_texture_coordinates(); // and texture coordinates
float* pPoints = (float*)m_stPointCloudConvert.pData;
ColorTable stColorTable = ColorTable::GetColorTable(m_enColorTable);
for (int i = 0; i < frame.nFrameLength / sizeof(float3); i++)
{
float3 fColor = stColorTable.get(pPoints[i * 3 + 2] / fZRatio);
glColor3f(fColor.x, fColor.y, fColor.z);
if (pPoints[i * 3 + 2])
{
// upload the point and texture coordinates only for points we have depth data for
glVertex3fv(&(pPoints[i * 3]));
//glTexCoord2fv(tex_coords[i]);
}
}
// OpenGL cleanup
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
}
void RenderImgWnd::SetColorTable(ColorTableType enType)
{
if (enType < ColorTableHue || enType > ColorTablePattern)
{
return;
}
m_enColorTable = enType;
}
void RenderImgWnd::Init3DRender()
{
if (nullptr == m_pRenderState)
{
m_pRenderState = std::make_shared<glfw_state>();
this->on_left_mouse = [&](bool pressed)
{
m_pRenderState->ml = pressed;
};
this->on_mouse_scroll = [&](double xoffset, double yoffset)
{
m_pRenderState->offset_x -= static_cast<float>(xoffset);
m_pRenderState->offset_y -= static_cast<float>(yoffset);
};
this->on_mouse_move = [&](double x, double y)
{
if (m_pRenderState->ml)
{
m_pRenderState->yaw -= (x - m_pRenderState->last_x);
m_pRenderState->yaw = max(m_pRenderState->yaw, -350.0);
m_pRenderState->yaw = min(m_pRenderState->yaw, +350.0);
m_pRenderState->pitch += (y - m_pRenderState->last_y);
m_pRenderState->pitch = max(m_pRenderState->pitch, -350.0);
m_pRenderState->pitch = min(m_pRenderState->pitch, +350.0);
}
m_pRenderState->last_x = x;
m_pRenderState->last_y = y;
};
this->on_key_release = [&](int key)
{
if (key == 32) // Escape
{
m_pRenderState->yaw = m_pRenderState->pitch = 0; m_pRenderState->offset_x = m_pRenderState->offset_y = 0.0;
}
};
}
}
static ColorTable hue{ {
{ 255, 0, 0 },
{ 255, 255, 0 },
{ 0, 255, 0 },
{ 0, 255, 255 },
{ 0, 0, 255 },
{ 255, 0, 255 },
{ 255, 0, 0 },
} };
static ColorTable jet{ {
{ 0, 0, 255 },
{ 0, 255, 255 },
{ 255, 255, 0 },
{ 255, 0, 0 },
{ 50, 0, 0 },
} };
static ColorTable classic{ {
{ 30, 77, 203 },
{ 25, 60, 192 },
{ 45, 117, 220 },
{ 204, 108, 191 },
{ 196, 57, 178 },
{ 198, 33, 24 },
} };
static ColorTable grayscale{ {
{ 255, 255, 255 },
{ 0, 0, 0 },
} };
static ColorTable inv_grayscale{ {
{ 0, 0, 0 },
{ 255, 255, 255 },
} };
static ColorTable biomes{ {
{ 0, 0, 204 },
{ 204, 230, 255 },
{ 255, 255, 153 },
{ 170, 255, 128 },
{ 0, 153, 0 },
{ 230, 242, 255 },
} };
static ColorTable cold{ {
{ 230, 247, 255 },
{ 0, 92, 230 },
{ 0, 179, 179 },
{ 0, 51, 153 },
{ 0, 5, 15 }
} };
static ColorTable warm{ {
{ 255, 255, 230 },
{ 255, 204, 0 },
{ 255, 136, 77 },
{ 255, 51, 0 },
{ 128, 0, 0 },
{ 10, 0, 0 }
} };
static ColorTable quantized{ {
{ 255, 255, 255 },
{ 0, 0, 0 },
}, 6 };
static ColorTable pattern{ {
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
{ 255, 255, 255 },
{ 0, 0, 0 },
} };
ColorTable& ColorTable::GetColorTable(ColorTableType enType)
{
switch (enType)
{
case RenderImage::ColorTableHue:
return hue;
break;
case RenderImage::ColorTableJet:
return jet;
break;
case RenderImage::ColorTableClassic:
return classic;
break;
case RenderImage::ColorTableGrayScale:
return grayscale;
break;
case RenderImage::ColorTableBiomes:
return biomes;
break;
case RenderImage::ColorTableCold:
return cold;
break;
case RenderImage::ColorTableWarm:
return warm;
break;
case RenderImage::ColorTableQuant:
return quantized;
break;
case RenderImage::ColorTablePattern:
return pattern;
break;
default:
break;
}
return ColorTable();
}
ColorTable::ColorTable(std::map<float, float3> map, int steps)
: _map(map)
{
initialize(steps);
}
ColorTable::ColorTable(const std::vector<float3>& values, int steps)
{
for (size_t i = 0; i < values.size(); i++)
{
_map[(float)i / (values.size() - 1)] = values[i];
}
initialize(steps);
}
ColorTable::ColorTable()
{}
float3 ColorTable::calc(float value) const
{
if (_map.size() == 0) return{ value, value, value };
// if we have exactly this value in the map, just return it
if (_map.find(value) != _map.end()) return _map.at(value);
// if we are beyond the limits, return the first/last element
if (value < _map.begin()->first) return _map.begin()->second;
if (value > _map.rbegin()->first) return _map.rbegin()->second;
auto lower = _map.lower_bound(value) == _map.begin() ? _map.begin() : --(_map.lower_bound(value));
auto upper = _map.upper_bound(value);
auto t = (value - lower->first) / (upper->first - lower->first);
auto c1 = lower->second;
auto c2 = upper->second;
return lerp(c1, c2, t);
}
void ColorTable::initialize(int steps)
{
if (_map.size() == 0) return;
_min = _map.begin()->first;
_max = _map.rbegin()->first;
_cache.resize(steps + 1);
for (int i = 0; i <= steps; i++)
{
auto t = (float)i / steps;
auto x = _min + t*(_max - _min);
_cache[i] = calc(x);
}
// Save size and data to avoid STL checks penalties in DEBUG
_size = _cache.size();
_data = _cache.data();
}
bool ConvertImageData(const RIFrameInfo& stSrcImageInfo, RIFrameInfo& stDstImageInfo, ColorTableType enColorTableType)
{
if (RIPixelType_RGB8_Packed == stDstImageInfo.enPixelType)
{
if (RIPixelType_Mono8 == stSrcImageInfo.enPixelType)
{
return ConvertMono8_2_RGB(stSrcImageInfo.pData,
stSrcImageInfo.nWidth,
stSrcImageInfo.nHeight,
stDstImageInfo.pData);
}
else if (RIPixelType_Coord3D_C16 == stSrcImageInfo.enPixelType)
{
return ConvertC16_2_RGB(stSrcImageInfo.pData,
stSrcImageInfo.nWidth,
stSrcImageInfo.nHeight,
stDstImageInfo.pData,
ColorTable::GetColorTable(enColorTableType));
}
else if (RIPixelType_RGB8_Planar == stSrcImageInfo.enPixelType)
{
return ConvertRGB8P_2_RGB(stSrcImageInfo.pData,
stSrcImageInfo.nWidth,
stSrcImageInfo.nHeight,
stDstImageInfo.pData);
}
else if (RIPixelType_RGB8_Packed == stSrcImageInfo.enPixelType)
{
return ConvertRGB_2_RGB(stSrcImageInfo.pData,
stSrcImageInfo.nWidth,
stSrcImageInfo.nHeight,
stDstImageInfo.pData);
}
else if (RIPixelType_RGBD_C16 == stSrcImageInfo.enPixelType)
{
return ConvertRGB24D16_2_RGB(stSrcImageInfo.pData,
stSrcImageInfo.nWidth,
stSrcImageInfo.nHeight,
stDstImageInfo.pData);
}
}
return false;
}
bool ConvertMono8_2_RGB(unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData)
{
if (nullptr == pSrcData || nullptr == pDstData)
{
return false;
}
int nByteCount = 0;
for (int nHeightIndex = 0; nHeightIndex < nHeight; ++nHeightIndex)
{
for (int nWidthIndex = 0; nWidthIndex < nWidth; ++nWidthIndex)
{
int nDataIndex = nHeightIndex * nWidth + nWidthIndex;
pDstData[nByteCount++] = pSrcData[nDataIndex];
pDstData[nByteCount++] = pSrcData[nDataIndex];
pDstData[nByteCount++] = pSrcData[nDataIndex];
}
while (nByteCount % 4)
{
nByteCount++;
}
}
return true;
}
bool ConvertC16_2_RGB(unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData, ColorTable& stColorTable)
{
if (nullptr == pSrcData || nullptr == pDstData)
{
return false;
}
int nDepth = 0;
int nMax = INT_MIN;
int nMin = INT_MAX;
short* pValue = (short*)pSrcData;
for (int i = 0; i < nWidth * nHeight; ++i)
{
nDepth = pValue[i];
if (C16_INVALID_VALUE == nDepth)
{
continue;
}
if (nDepth > nMax)
{
nMax = nDepth;
}
if (nDepth < nMin)
{
nMin = nDepth;
}
}
int nCurRange = nMax - nMin;
int nByteCount = 0;
for (int nHeightIndex = 0; nHeightIndex < nHeight; ++nHeightIndex)
{
for (int nWidthIndex = 0; nWidthIndex < nWidth; ++nWidthIndex)
{
int nDataIndex = nHeightIndex * nWidth + nWidthIndex;
nDepth = pValue[nDataIndex];
if (C16_INVALID_VALUE == nDepth || 0 == nDepth)
{
pDstData[nByteCount++] = 0;
pDstData[nByteCount++] = 0;
pDstData[nByteCount++] = 0;
continue;
}
if (nCurRange != 0)
{
float fTmpPosValue = (nDepth - nMin) / (1.0 * nCurRange);
if (fTmpPosValue < 0)
{
fTmpPosValue = 0;
}
if (fTmpPosValue > 1)
{
fTmpPosValue = 1.0;
}
float3 stColor = stColorTable.get(fTmpPosValue);
pDstData[nByteCount++] = stColor.x;
pDstData[nByteCount++] = stColor.y;
pDstData[nByteCount++] = stColor.z;
continue;
}
float3 stColor = stColorTable.get(0);
pDstData[nByteCount++] = stColor.x;
pDstData[nByteCount++] = stColor.y;
pDstData[nByteCount++] = stColor.z;
}
while (nByteCount % 4)
{
nByteCount++;
}
}
return true;
}
bool ConvertRGB8P_2_RGB(unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData)
{
if (nullptr == pSrcData || nullptr == pDstData)
{
return false;
}
int nStepDist = nWidth * nHeight;
int nByteCount = 0;
for (int nHeightIndex = 0; nHeightIndex < nHeight; ++nHeightIndex)
{
for (int nWidthIndex = 0; nWidthIndex < nWidth; ++nWidthIndex)
{
int nDataIndex = nHeightIndex * nWidth + nWidthIndex;
pDstData[nByteCount++] = pSrcData[0 * nStepDist + nDataIndex];
pDstData[nByteCount++] = pSrcData[1 * nStepDist + nDataIndex];
pDstData[nByteCount++] = pSrcData[2 * nStepDist + nDataIndex];
}
while (nByteCount % 4)
{
nByteCount++;
}
}
return true;
}
bool ConvertRGB_2_RGB(unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData)
{
if (nullptr == pSrcData || nullptr == pDstData)
{
return false;
}
if (nWidth % 4 == 0)
{
//宽度整除4无需转换
memcpy(pDstData, pSrcData, nWidth * nHeight * 3);
return true;
}
int nByteCount = 0;
for (int nHeightIndex = 0; nHeightIndex < nHeight; ++nHeightIndex)
{
for (int nWidthIndex = 0; nWidthIndex < nWidth; ++nWidthIndex)
{
int nDataIndex = nHeightIndex * nWidth + nWidthIndex;
pDstData[nByteCount++] = pSrcData[3 * nDataIndex + 0];
pDstData[nByteCount++] = pSrcData[3 * nDataIndex + 1];
pDstData[nByteCount++] = pSrcData[3 * nDataIndex + 2];
}
while (nByteCount % 4)
{
nByteCount++;
}
}
return true;
}
bool CalcEqualizedHist(const unsigned char* src, unsigned int sstep, unsigned int width, unsigned int height
, float low_thresh, float high_thresh, bool depth_only, unsigned int& min_elem, unsigned int& max_elem, std::vector<float> &equalized_hist)
{
if (low_thresh<0.0f || low_thresh>1.0f || high_thresh<0.0f || high_thresh>1.0f || low_thresh > high_thresh)
{
return 0;
}
vector<unsigned int> hist;
size_t size = (1 << (8 * sizeof(unsigned short)));
hist.resize(size);
//赋0效率待测试
memset(&hist[0], 0, hist.size()*sizeof(unsigned int));
unsigned int total_num = 0;
if (depth_only)
{
//src为16位深度图
for (int i = 0; i < height; ++i)
{
const unsigned short* s = (const unsigned short*)(src + i*sstep);
for (int j = 0; j < width; ++j)
{
unsigned short val = s[j];
//深度图0值为无效值
if (0 != val)
{
++hist[val];
++total_num;
}
}
}
}
else
{
//src为RGB24D16_Packed格式的图像数据(R,G,B,D1,D2...)
for (int i = 0; i < height; ++i)
{
const unsigned char* s = src + i*sstep;
for (int j = 0; j < width; ++j)
{
unsigned short val = (s[5 * j + 3]) + (s[5 * j + 4] << 8);
//深度图0值为无效值
if (0 != val)
{
++hist[val];
++total_num;
}
}
}
}
if (0 == total_num)
{
equalized_hist.resize(hist.size());
memset(&equalized_hist[0], 0, equalized_hist.size()*sizeof(float));
min_elem = max_elem = 0;
return true;
}
equalized_hist.resize(hist.size());
for (int i = 1; i < hist.size(); ++i)
{
hist[i] += hist[i - 1];
equalized_hist[i] = 1.0f*hist[i] / total_num;
}
//TODO:图像平滑后是否需要设置阈值
//在[0.01,0.99]范围内获取最大值和最小值,消除噪点影响
int min_val = 0;
int max_val = 0;
for (int i = 1; i < equalized_hist.size(); ++i)
{
if (equalized_hist[i] >= low_thresh)
{
min_val = i;
break;
}
}
for (int i = equalized_hist.size() - 1; i > 0; --i)
{
if (equalized_hist[i] <= high_thresh)
{
max_val = i;
break;
}
}
if (max_val < min_val)
{
max_val = min_val;
}
min_elem = min_val;
max_elem = max_val;
return true;
}
bool ConvertRGB24D16_2_RGB(unsigned char* pSrcData, int nWidth, int nHeight, unsigned char* pDstData)
{
vector<float> equalized_hist;
unsigned int min_val = 0;
unsigned int max_val = 0;
CalcEqualizedHist(pSrcData, nWidth * 5, nWidth, nHeight, 0.01, 0.99, false, min_val, max_val, equalized_hist);
//初始化颜色映射表
InitColorTable();
int nCurRange = max_val - min_val;
int nByteCount = 0;
for (int nHeightIndex = 0; nHeightIndex < nHeight; ++nHeightIndex)
{
for (int nWidthIndex = 0; nWidthIndex < nWidth; ++nWidthIndex)
{
int nDataIndex = nHeightIndex * nWidth + nWidthIndex;
unsigned short* pDepthValue = (unsigned short*)(pSrcData + nDataIndex * 5 + 3);
unsigned short nDepthValue = *pDepthValue;
if (nCurRange != 0 && nDepthValue != 0)
{
int color_index = 0;
if (nDepthValue <= min_val)
{
color_index = 255;
}
else if (nDepthValue >= max_val)
{
color_index = 0;
}
else
{
//综合考虑直方图均衡化和直方图正规化
color_index = (g_fContrastEnhance*(1 - equalized_hist[nDepthValue])
+ (1.0f - g_fContrastEnhance) * (max_val - nDepthValue) / nCurRange) * 255;
}
pDstData[nByteCount++] = g_fWeightedRatio * m_vecRGBDColorTable[color_index].x + (1 - g_fWeightedRatio) * pSrcData[nDataIndex * 5 + 0];
pDstData[nByteCount++] = g_fWeightedRatio * m_vecRGBDColorTable[color_index].y + (1 - g_fWeightedRatio) * pSrcData[nDataIndex * 5 + 1];
pDstData[nByteCount++] = g_fWeightedRatio * m_vecRGBDColorTable[color_index].z + (1 - g_fWeightedRatio) * pSrcData[nDataIndex * 5 + 2];
}
else
{
//使用RGB图像颜色
pDstData[nByteCount++] = pSrcData[nDataIndex * 5 + 0];
pDstData[nByteCount++] = pSrcData[nDataIndex * 5 + 1];
pDstData[nByteCount++] = pSrcData[nDataIndex * 5 + 2];
}
}
while (nByteCount % 4)
{
nByteCount++;
}
}
return true;
}
bool NormalizeABC32f(unsigned char* pSrcData, int nDataLen, unsigned char* pDstData, float* fZRatio, float fMinX, float fMaxX, float fMinY, float fMaxY)
{
if (nullptr == pSrcData || nullptr == pDstData)
{
return false;
}
int nPointNum = nDataLen / (sizeof(float) * 3);
std::vector<float> vecX(nPointNum);
std::vector<float> vecY(nPointNum);
std::vector<float> vecZ(nPointNum);
float* pSrcValue = (float*)pSrcData;
float* pDstValue = (float*)pDstData;
for (int nPntIndex = 0; nPntIndex < nPointNum; ++nPntIndex)
{
vecX[nPntIndex] = pSrcValue[nPntIndex * 3 + 0];
vecY[nPntIndex] = pSrcValue[nPntIndex * 3 + 1];
vecZ[nPntIndex] = pSrcValue[nPntIndex * 3 + 2];
}
auto funcCalcDistance = [](const std::vector<float>& vec, float& fMin, float& fMax) {
auto itMin = std::min_element(vec.begin(), vec.end());
auto itMax = std::max_element(vec.begin(), vec.end());
if (itMin != vec.end() && itMax != vec.end())
{
fMax = *itMax;
fMin = *itMin;
}
};
float fMinZ = 0.0f, fMaxZ = 0.0f;
if (fMinX >= fMaxX)
{
funcCalcDistance(vecX, fMinX, fMaxX);
}
if (fMinY >= fMaxY)
{
funcCalcDistance(vecY, fMinY, fMaxY);
}
funcCalcDistance(vecZ, fMinZ, fMaxZ);
float fDistX = fMaxX - fMinX;
float fDistY = fMaxY - fMinY;
float fDistZ = fMaxZ - fMinZ;
float fMaxDist = max(max(fDistX, fDistY), fDistZ);
if (fZRatio)
{
*fZRatio = fDistZ / fMaxDist;
}
if (fDistX > 0 && fDistY > 0 && fDistZ > 0)
{
for (int nPntIndex = 0; nPntIndex < nPointNum; ++nPntIndex)
{
pDstValue[nPntIndex * 3 + 0] = (vecX[nPntIndex] - fMinX) / fDistX * (fDistX / fMaxDist) * 2 - 1.0f;
pDstValue[nPntIndex * 3 + 1] = (vecY[nPntIndex] - fMinY) / fDistY * (fDistY / fMaxDist) * 2 - 1.0f;
pDstValue[nPntIndex * 3 + 2] = (vecZ[nPntIndex] - fMinZ) / fDistZ * (fDistZ / fMaxDist);
}
return true;
}
return false;
}
};