fast/3rdparty/hikvision/rgbd_camera/inc/RenderWindow.hpp

1265 lines
40 KiB
C++
Raw Normal View History

2025-01-20 10:30:01 +08:00

#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;
}
};