#include "Export.h"
#include "VolumeDataPreProcessor.h"
///
/// 获取错误详情
///
///
///
///
///
extern "C" __declspec(dllexport) void GetErrorCodeAndMsg(ErrorCode & errorCode, char* errorMsg, const int errorMaxLen)
{
ErrorMsg::GetErrorMsg(errorCode, errorMsg, errorMaxLen);
}
///
/// 图像数据解码
///
///
///
///
///
///
extern "C" __declspec(dllexport) bool ImDataDecode(const uint8_t * srcImgData, const int srcDataSize,
uint8_t * dstImgData, const int dstDataSize, ImreadModes imReadMode)
{
// 如果失败,已经在函数内部写了ErrorMsg了,不用再重复赋值
return _encodeDecode.Decode(srcImgData, srcDataSize, dstImgData, dstDataSize, imReadMode);
}
///
/// 图像数据编码
///
///
///
///
///
///
///
///
extern "C" __declspec(dllexport) bool ImDataEncode(ImageInfo srcImgInfo, ImwriteExtension extension,
ImwriteParam * imwriteParams, int paramCount, uint8_t * dstImgData, int& dstDataSize)
{
// 如果失败,已经在函数内部写了ErrorMsg了,不用再重复赋值
return _encodeDecode.Encode(srcImgInfo, extension, imwriteParams, paramCount, dstImgData, dstDataSize);
}
///
/// 将直线扫查的数据转成均一立方体
///
///
///
///
extern "C" __declspec(dllexport) bool StraightScanDataToUniformCube(VolumeDataPreProcessorInfo volumeInfo,
uint8_t * dstVolumeData)
{
try
{
// 创建容器
VolumeDataPreProcessor preprocessor = VolumeDataPreProcessor(2, volumeInfo);
// 根据目标图像数量逐帧插值
// 考虑到是直线扫查得到的数据,因此在求每一个插值帧的每个像素点灰度时,
// 相当于xy完全落在网格点处,只有z可能会落在前后帧之间,因此只需要在z方向取前后帧的xy位置处的灰度,
// 直接进行线性插值即可获得所需灰度
int imgCount = volumeInfo.origImgCount;
int dstImgCount = volumeInfo.desiredImgCount;
if(dstImgCount <=1)
{
char strMsgBuff[32];
std::snprintf(strMsgBuff, 32, "unexpected desiredImgCount value ( %i ) ", dstImgCount);
ErrorMsg::SetErrorMsg(StraightScanDataUniformError, { strMsgBuff });
return false;
}
float ratio = (imgCount -1) * 1.0f / (dstImgCount -1);
int bytePerPixel = ImageHelper::GetBytesPerPixel(volumeInfo.colorType);
int dstBytePerImg = volumeInfo.desiredImgWidth * volumeInfo.desiredImgHeight * bytePerPixel;
uint8_t* pDstData;
for (int ni = 0; ni < dstImgCount; ni++)
{
float position = ratio * ni;
int posFront = floor(position);
float posRatio = position - posFront;
// 很靠近前一个点或后一个点,就直接只参考前一个点或后一个点的灰度即可
// 因为就算后一个点的灰度是255,乘以比值0.001后,对当前位置处也只有0.255的贡献,可以忽略不计
if (posRatio < 0.001)
{
posRatio = 0;
}
if (posRatio > 0.99)
{
posRatio = 1;
}
int posBack = posFront + 1;
// 不要超过范围
posFront = std::min(imgCount-1,std::max(0, posFront));
posBack = std::min(imgCount - 1, std::max(0, posBack));
cv::Mat dstImg;
// 只取前一帧图,直接复制即可
if (posRatio == 0)
{
dstImg = preprocessor.GetImage(posFront);
}
// 只取后一帧图,直接复制即可
else if (posRatio == 1)
{
dstImg = preprocessor.GetImage(posBack);
}
// 需要取前后各一帧,逐像素进行插值
else
{
auto frontImg = preprocessor.GetImage(posFront);
auto backImg = preprocessor.GetImage(posBack);
dstImg = UniformHelper::LinearInterpolation(frontImg, backImg, posRatio);
}
// 将dstImg中的数据复制到所需位置
pDstData = dstVolumeData + ni * dstBytePerImg;
std::memcpy(pDstData, dstImg.data, dstBytePerImg);
}
return true;
}
catch (const std::exception& ex)
{
ErrorMsg::SetErrorMsg(StraightScanDataUniformError,{ ex.what() });
return false;
}
}
///
/// 获取立方体的六个表面
///
///
///
///
///
extern "C" __declspec(dllexport) bool GetSurfacePicsFromUniformCube(UniformVolumeDataInfo volumeDataInfo,
int surfaceNum, SurfacePicInfo * surfaceInfos)
{
try
{
int x = volumeDataInfo.x;
int y = volumeDataInfo.y;
int z = volumeDataInfo.z;
float spacing = volumeDataInfo.spacing;
// 创建SliceHelper
SliceHelper _sliceHelper;
// 把体数据加载到SliceHelper里
_sliceHelper.LoadVolumeData(volumeDataInfo);
// 逐个表面获取
for(int ni=0; ni< surfaceNum;ni++)
{
auto surfaceInfo = surfaceInfos[ni];
auto surfaceType = surfaceInfo.surfaceType;
auto imgInfo = surfaceInfo.imgInfo;
AxisName axisName = X;
int intersectionVal = 0;
switch(surfaceType)
{
case Right:
axisName = X;
intersectionVal = x-1;
break;
case Left:
axisName = X;
intersectionVal = 0;
break;
case Behind:
axisName = Z;
intersectionVal = z-1;
break;
case Front:
axisName = Z;
intersectionVal = 0;
break;
case Top:
axisName = Y;
intersectionVal = 0;
break;
case Bottom:
axisName = Y;
intersectionVal = y-1;
break;
}
_sliceHelper.GetVerticalToAxisSlicePlaneImage(axisName, intersectionVal,imgInfo);
// 赋值回去
surfaceInfos[ni].imgInfo.width = imgInfo.width;
surfaceInfos[ni].imgInfo.height = imgInfo.height;
surfaceInfos[ni].imgInfo.colorType = imgInfo.colorType;
int imgByteCounts = imgInfo.width * imgInfo.height * ImageHelper::GetBytesPerPixel(imgInfo.colorType);
}
return true;
}
catch(const std::exception & ex)
{
ErrorMsg::SetErrorMsg(GetSurfaceError, { ex.what() });
return false;
}
}
///
/// 基于ITK的x方向融合
///
///
///
///
extern "C" __declspec(dllexport) bool ITKBasedFusionAlongX(UniformVolumeDataInfo * volumeDataInfos, int volumeDataCount,
UniformVolumeDataInfo & fusedDataInfo)
{
if (volumeDataCount < 2)
{
char strMsgBuff[32];
std::snprintf(strMsgBuff, 32, "unexpected volumeDataCount ( %i ).", volumeDataCount);
ErrorMsg::SetErrorMsg(FusionError, { strMsgBuff });
return false;
}
// 直接按照给入的顺序,第一个作为基础体数据,其他顺序与其融合
FusionHelper fusionHelper = FusionHelper();
const int baseVolumeIndex = 0;
if (!fusionHelper.LoadBaseVolumeData(volumeDataInfos[baseVolumeIndex]))
{
// 已经在函数内部写了ErrorMsg了
return false;
}
for (int ni = 1; ni < volumeDataCount; ni++)
{
if(!fusionHelper.FuseWithAnotherVolumeData(volumeDataInfos[ni]))
{
// 已经在函数内部写了ErrorMsg了,不用再重复赋值
return false;
}
}
// 取出融合后的结果
if(!fusionHelper.GetFusedVolumeData(fusedDataInfo))
{
// 已经在函数内部写了ErrorMsg了,不用再重复赋值
return false;
}
return true;
}
///
/// 图像数据编码并保存至本地
///
///
///
///
///
///
///
extern "C" __declspec(dllexport) bool ImDataSave(ImageInfo srcImgInfo, ImwriteExtension extension,
ImwriteParam * imwriteParams, int paramCount, const char* savePath)
{
// 如果失败,已经在函数内部写了ErrorMsg了,不用再重复赋值
return _encodeDecode.SaveImage(srcImgInfo, extension, imwriteParams, paramCount, savePath);
}