@@ -0,0 +1,21 @@ | |||
MIT License | |||
Copyright (c) 2020 UltimageTK | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. |
@@ -0,0 +1,112 @@ | |||
/****************************************************************************** | |||
* Copyright (C), 2017-2019,Advanced Technology Institute of Suzhou. | |||
* THIS IS AN UNPUBLISHED WORK CONTAINING CONFIDENTIAL AND PROPRIETARY | |||
* | |||
******************************************************************************* | |||
* File Name: LabelAnalysis.h | |||
* Author: qh.zhang@atisz.ac.cn | |||
* Version: 1.0.0 | |||
* Date: 2020-3-23 | |||
* Description: LRS结构是UltImageTK为了方便保存和读取已标注文件而定义的一种序列化到本地的格式 | |||
* History: | |||
******************************************************************************/ | |||
#pragma once | |||
#include <string.h> | |||
#include <vector> | |||
#include <list> | |||
#include <map> | |||
#ifdef LABELANALYSIS_EXPORTS | |||
#define EXPORTS_LABEL _declspec(dllexport) | |||
#else | |||
#define EXPORTS_LABEL _declspec(dllimport) | |||
#endif | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
namespace LabelAnalysis | |||
{ | |||
/******************************************************** | |||
* @struct : Vertex | |||
* @brief : 一个点的信息 | |||
* @details : 一个点的位置和物理值(HU) | |||
*********************************************************/ | |||
struct Vertex | |||
{ | |||
float fX; //在当前视图下的x坐标 | |||
float fY; //在当前视图下的y坐标 | |||
int nValue; //HU值 | |||
}; | |||
/******************************************************** | |||
* @struct : Target | |||
* @brief : 每一个目标的信息 | |||
* @details : 标记好的每一个目标ROI的信息 | |||
*********************************************************/ | |||
struct Target | |||
{ | |||
std::string strTargetName; //目标类型-标签值 | |||
std::string strTargetDisc; //目标描述-标签描述 | |||
int nTargetID; //目标在当前视图当前层的ID | |||
int nTargetType; //目标几何形状类型 | |||
std::list<Vertex> lstVertex; //目标轮廓点集 | |||
}; | |||
/******************************************************** | |||
* @struct : FileInfo | |||
* @brief : 源图像文件的信息 | |||
* @details : 源文件中一些相对比较重要的信息 | |||
*********************************************************/ | |||
struct FileInfo | |||
{ | |||
std::string strFilePath; //源文件路径,或文件夹路径 | |||
std::string strPatientName; //患者名 | |||
std::string strPatientAge; //患者年龄 | |||
std::string strPatientSex; //患者性别 | |||
int nFileType; //文件类型 | |||
int nWidth; //宽 | |||
int nHeight; //高 | |||
int nThickness; //层数 | |||
float fSpacing; //间隔比例 | |||
}; | |||
/******************************************************** | |||
* @struct : AllLabelInfo | |||
* @brief : 一个文件或图像序列的所有信息 | |||
* @details : 包含源图像文件的信息,已标注的标签信息,以及标注在各个视图面上的ROI信息 | |||
*********************************************************/ | |||
struct AllLabelInfo | |||
{ | |||
int nCurVersion; //本版 | |||
FileInfo stFileInfo; //读取的文件信息 | |||
std::map<std::string, int> mapLabelProperty; //label的颜色和定义 | |||
std::map<int, std::map<int, Target>> mapSPTargets; //矢状面,帧号和目标列表 | |||
std::map<int, std::map<int, Target>> mapCPTargets; //冠状面,帧号和目标列表 | |||
std::map<int, std::map<int, Target>> mapTPTargets; //横断面,帧号和目标列表 | |||
}; | |||
/******************************************************** | |||
* @function : ReadLabelFile | |||
* @brief : 读取pPath路径下的lrs文件 | |||
* @input : pPath 读路径 | |||
* @output : stAllLabelInfo LRS数据结构 | |||
* @return : bool 成功与否 | |||
*********************************************************/ | |||
EXPORTS_LABEL bool ReadLabelFile(char* pPath, AllLabelInfo &stAllLabelInfo); | |||
/******************************************************** | |||
* @function : WriteLabelFile | |||
* @brief : 往pPath路径写lrs文件 | |||
* @input : pPath 写路径 | |||
* @input : stAllLabelInfo LRS数据结构 | |||
* @return : bool 成功与否 | |||
*********************************************************/ | |||
EXPORTS_LABEL bool WriteLabelFile(char* pPath, AllLabelInfo stAllLabelInfo); | |||
} | |||
} | |||
#endif |
@@ -0,0 +1,45 @@ | |||
| |||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||
# Visual Studio 15 | |||
VisualStudioVersion = 15.0.28307.572 | |||
MinimumVisualStudioVersion = 10.0.40219.1 | |||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UltimageTK", "UltimageTK\UltimageTK.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" | |||
EndProject | |||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LabelAnalysis", "LabelAnalysis\LabelAnalysis.vcxproj", "{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}" | |||
EndProject | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
Debug|Any CPU = Debug|Any CPU | |||
Debug|x64 = Debug|x64 | |||
Debug|x86 = Debug|x86 | |||
Release|Any CPU = Release|Any CPU | |||
Release|x64 = Release|x64 | |||
Release|x86 = Release|x86 | |||
EndGlobalSection | |||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Any CPU.ActiveCfg = Debug|x64 | |||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64 | |||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|x64 | |||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.ActiveCfg = Debug|x64 | |||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Any CPU.ActiveCfg = Release|x64 | |||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|x64 | |||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|x64 | |||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.ActiveCfg = Release|x64 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Debug|Any CPU.ActiveCfg = Debug|Win32 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Debug|x64.ActiveCfg = Debug|x64 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Debug|x64.Build.0 = Debug|x64 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Debug|x86.ActiveCfg = Debug|Win32 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Debug|x86.Build.0 = Debug|Win32 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Release|Any CPU.ActiveCfg = Release|Win32 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Release|x64.ActiveCfg = Release|x64 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Release|x64.Build.0 = Release|x64 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Release|x86.ActiveCfg = Release|Win32 | |||
{3371EEF4-BFB6-4EFB-A512-5975258FB4EE}.Release|x86.Build.0 = Release|Win32 | |||
EndGlobalSection | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||
EndGlobalSection | |||
GlobalSection(ExtensibilityGlobals) = postSolution | |||
SolutionGuid = {A6DBC197-F496-4D38-923E-17611289B7BF} | |||
EndGlobalSection | |||
EndGlobal |
@@ -0,0 +1,30 @@ | |||
/******************************************************** | |||
* @file : AboutDlg.cpp | |||
* @brief : brief | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-7-9 | |||
*********************************************************/ | |||
#include "AboutDlg.h" | |||
AboutDlg::AboutDlg(QWidget *parent) | |||
: QDialog(parent) | |||
{ | |||
ui.setupUi(this); | |||
} | |||
AboutDlg::~AboutDlg() | |||
{ | |||
} | |||
/******************************************************** | |||
* @function : changeLanguage | |||
* @brief : ±ä¸üÓïÑÔ | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void AboutDlg::changeLanguage() | |||
{ | |||
ui.retranslateUi(this); | |||
} |
@@ -0,0 +1,24 @@ | |||
/******************************************************** | |||
* @file : AboutDlg.h | |||
* @brief : brief | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-7-9 | |||
*********************************************************/ | |||
#pragma once | |||
#include <QDialog> | |||
#include "ui_AboutDlg.h" | |||
class AboutDlg : public QDialog | |||
{ | |||
Q_OBJECT | |||
public: | |||
AboutDlg(QWidget *parent = Q_NULLPTR); | |||
~AboutDlg(); | |||
//ąä¸üÓďŃÔ | |||
void changeLanguage(); | |||
private: | |||
Ui::AboutDlg ui; | |||
}; |
@@ -0,0 +1,84 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<ui version="4.0"> | |||
<class>AboutDlg</class> | |||
<widget class="QDialog" name="AboutDlg"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>0</x> | |||
<y>0</y> | |||
<width>255</width> | |||
<height>107</height> | |||
</rect> | |||
</property> | |||
<property name="sizePolicy"> | |||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> | |||
<horstretch>0</horstretch> | |||
<verstretch>0</verstretch> | |||
</sizepolicy> | |||
</property> | |||
<property name="minimumSize"> | |||
<size> | |||
<width>255</width> | |||
<height>107</height> | |||
</size> | |||
</property> | |||
<property name="maximumSize"> | |||
<size> | |||
<width>255</width> | |||
<height>107</height> | |||
</size> | |||
</property> | |||
<property name="windowTitle"> | |||
<string>关于 UltImageTK</string> | |||
</property> | |||
<layout class="QHBoxLayout" name="horizontalLayout"> | |||
<item> | |||
<layout class="QVBoxLayout" name="verticalLayout"> | |||
<item> | |||
<widget class="QLabel" name="label"> | |||
<property name="styleSheet"> | |||
<string notr="true">font: 9pt "微软雅黑";</string> | |||
</property> | |||
<property name="text"> | |||
<string>UltImageTK</string> | |||
</property> | |||
</widget> | |||
</item> | |||
<item> | |||
<widget class="QLabel" name="label_2"> | |||
<property name="styleSheet"> | |||
<string notr="true">font: 9pt "微软雅黑";</string> | |||
</property> | |||
<property name="text"> | |||
<string>版本1.0.1</string> | |||
</property> | |||
</widget> | |||
</item> | |||
<item> | |||
<widget class="QLabel" name="label_5"> | |||
<property name="styleSheet"> | |||
<string notr="true">font: 9pt "微软雅黑";</string> | |||
</property> | |||
<property name="text"> | |||
<string>©2019 苏州中科华影健康科技有限公司</string> | |||
</property> | |||
</widget> | |||
</item> | |||
<item> | |||
<widget class="QLabel" name="label_4"> | |||
<property name="styleSheet"> | |||
<string notr="true">font: 9pt "微软雅黑";</string> | |||
</property> | |||
<property name="text"> | |||
<string>保留所有权利</string> | |||
</property> | |||
</widget> | |||
</item> | |||
</layout> | |||
</item> | |||
</layout> | |||
</widget> | |||
<layoutdefault spacing="6" margin="11"/> | |||
<resources/> | |||
<connections/> | |||
</ui> |
@@ -0,0 +1,105 @@ | |||
/******************************************************** | |||
* @file : AllSettings.cpp | |||
* @brief : | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-5-20 | |||
*********************************************************/ | |||
#include "AllSettings.h" | |||
AllSettings* AllSettings::m_pInstance = nullptr; | |||
/******************************************************** | |||
* @function : 构造函数 | |||
* @brief : brief | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
AllSettings::AllSettings() | |||
{ | |||
} | |||
AllSettings::~AllSettings() | |||
{ | |||
} | |||
/******************************************************** | |||
* @function : UpdateColorMap | |||
* @brief : 更新标签颜色表 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void AllSettings::UpdateColorMap(const std::map<std::string, int> mapLabelProperty) | |||
{ | |||
if (mapLabelProperty.empty()) | |||
{ | |||
return; | |||
} | |||
m_mapColor.clear(); | |||
for each (auto var in mapLabelProperty) | |||
{ | |||
m_mapColor[QString::fromLocal8Bit(var.first.c_str())] = var.second; | |||
} | |||
m_strCurLabel = m_mapColor.firstKey(); | |||
} | |||
/******************************************************** | |||
* @function : GetColorByLabel | |||
* @brief : 根据标签名获取颜色 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
QColor AllSettings::GetColorByLabel(QString str) | |||
{ | |||
if (m_mapColor.find(str) != m_mapColor.end()) | |||
{ | |||
return m_mapColor[str]; | |||
} | |||
else | |||
{ | |||
return QColor(255, 255, 255); | |||
} | |||
} | |||
/******************************************************** | |||
* @function : SetCurLabel | |||
* @brief : 更新当前标签名 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void AllSettings::SetCurLabel(QString strLabel) | |||
{ | |||
m_strCurLabel = strLabel; | |||
} | |||
/******************************************************** | |||
* @function : GetCurLabelAndColor | |||
* @brief : 获取当前标签和颜色 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void AllSettings::GetCurLabelAndColor(QString &str, QColor &color) | |||
{ | |||
str = m_strCurLabel; | |||
color = m_mapColor[m_strCurLabel]; | |||
} | |||
/******************************************************** | |||
* @function : GetCurColor | |||
* @brief : 获取当前颜色 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
QColor AllSettings::GetCurColor() | |||
{ | |||
return m_mapColor[m_strCurLabel]; | |||
} | |||
@@ -0,0 +1,60 @@ | |||
/******************************************************** | |||
* @file : AllSettings.h | |||
* @brief : | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-5-20 | |||
*********************************************************/ | |||
#pragma once | |||
#include <QColor> | |||
#include <QMap> | |||
/******************************************************** | |||
* @class : AllSettings | |||
* @brief : brief | |||
* @details : | |||
*********************************************************/ | |||
class AllSettings | |||
{ | |||
public: | |||
static AllSettings* getInstance() | |||
{ | |||
if (nullptr == m_pInstance) | |||
{ | |||
m_pInstance = new AllSettings; | |||
} | |||
return m_pInstance; | |||
} | |||
static void releaseInstance() | |||
{ | |||
if (nullptr != m_pInstance) | |||
{ | |||
delete m_pInstance; | |||
m_pInstance = nullptr; | |||
} | |||
} | |||
//更新颜色表 | |||
void UpdateColorMap(const std::map<std::string, int> mapLabelProperty); | |||
//根据标签获取颜色 | |||
QColor GetColorByLabel(QString str); | |||
//设置当前标签名 | |||
void SetCurLabel(QString strLabel); | |||
//获取当前标签和颜色 | |||
void GetCurLabelAndColor(QString &str, QColor &color); | |||
//获取当前颜色 | |||
QColor GetCurColor(); | |||
private: | |||
AllSettings(); | |||
~AllSettings(); | |||
private: | |||
static AllSettings* m_pInstance; | |||
QMap<QString, QColor> m_mapColor; //颜色标签表 | |||
QString m_strCurLabel; //当前标签名 | |||
}; |
@@ -0,0 +1,70 @@ | |||
/******************************************************** | |||
* @file : ConfigHelper.cpp | |||
* @brief : brief | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-8-6 | |||
*********************************************************/ | |||
#include <QSettings> | |||
#include "ConfigHelper.h" | |||
#define CONFIG_FILE "./config.ini" | |||
ConfigHelper * ConfigHelper::m_pInstance = nullptr; | |||
ConfigHelper::ConfigHelper() | |||
{ | |||
} | |||
ConfigHelper::~ConfigHelper() | |||
{ | |||
} | |||
/******************************************************** | |||
* @function : readConfig | |||
* @brief : 读配置 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
bool ConfigHelper::readConfig(AllConfig &stAllConfig) | |||
{ | |||
//设置好格式和编码 | |||
QSettings stSetting(CONFIG_FILE, QSettings::IniFormat); | |||
stSetting.setIniCodec("GBK"); | |||
//在AllConfig组中读取各个项 | |||
stSetting.beginGroup("AllConfig"); | |||
m_stAllConfig.emLanguage = (QLocale::Language)stSetting.value("Language").toInt(); | |||
stSetting.endGroup(); | |||
//简单校验一下,如果用户名是空的,返回错误 | |||
if (m_stAllConfig.emLanguage<=0) | |||
{ | |||
return false; | |||
} | |||
stAllConfig = m_stAllConfig; | |||
return true; | |||
} | |||
/******************************************************** | |||
* @function : writeConfig | |||
* @brief : 写配置 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
bool ConfigHelper::writeConfig(const AllConfig &stAllConfig) | |||
{ | |||
//设置好格式和编码 | |||
QSettings stSetting(CONFIG_FILE, QSettings::IniFormat); | |||
stSetting.setIniCodec("GBK"); | |||
m_stAllConfig = stAllConfig; | |||
//写AllConfig组中各个项 | |||
stSetting.beginGroup("AllConfig"); | |||
stSetting.setValue("Language", m_stAllConfig.emLanguage); | |||
stSetting.endGroup(); | |||
return true; | |||
} |
@@ -0,0 +1,66 @@ | |||
/******************************************************** | |||
* @file : ConfigHelper.h | |||
* @brief : brief | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-8-6 | |||
*********************************************************/ | |||
#pragma once | |||
#include <QLocale> | |||
/******************************************************** | |||
* @struct : AllConfig | |||
* @brief : 配置文件中的各项 | |||
* @details : | |||
*********************************************************/ | |||
struct AllConfig | |||
{ | |||
QLocale::Language emLanguage; //用户名 | |||
AllConfig() | |||
{ | |||
emLanguage = QLocale::Language::Chinese; | |||
} | |||
}; | |||
/******************************************************** | |||
* @class : ConfigHelper | |||
* @brief : 配置文件帮助单例 | |||
* @details : | |||
*********************************************************/ | |||
class ConfigHelper | |||
{ | |||
ConfigHelper(); | |||
~ConfigHelper(); | |||
public: | |||
static ConfigHelper* getInstance() | |||
{ | |||
if (nullptr == m_pInstance) | |||
{ | |||
m_pInstance = new ConfigHelper; | |||
} | |||
return m_pInstance; | |||
} | |||
static void releaseInstance() | |||
{ | |||
if (nullptr != m_pInstance) | |||
{ | |||
delete m_pInstance; | |||
m_pInstance = nullptr; | |||
} | |||
} | |||
public: | |||
//读配置文件 | |||
bool readConfig(AllConfig &stAllConfig); | |||
//写配置文件 | |||
bool writeConfig(const AllConfig &stAllConfig); | |||
private: | |||
static ConfigHelper* m_pInstance; //单例句柄 | |||
AllConfig m_stAllConfig; //所有配置信息 | |||
}; | |||
@@ -0,0 +1,612 @@ | |||
/******************************************************** | |||
* @file : DataLoad.cpp | |||
* @brief : | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-4-25 | |||
*********************************************************/ | |||
#include <QFileInfo> | |||
#include <QDir> | |||
#include "DataLoad.h" | |||
#include "dcmtk/config/osconfig.h" | |||
#include "dcmtk/dcmdata/dctk.h" | |||
#include "opencv2/opencv.hpp" | |||
#include "ImageDataManager.h" | |||
#include "itkImageFileReader.h" | |||
#include "itkImageFileWriter.h" | |||
#include "itkRescaleIntensityImageFilter.h" | |||
#include "itkImageSeriesReader.h" | |||
#include "itkImageFileWriter.h" | |||
#include "itkGDCMImageIOFactory.h" | |||
#include "itkNiftiImageIOFactory.h" | |||
#include "itkJPEGImageIOFactory.h" | |||
#include "itkPNGImageIOFactory.h" | |||
#include "itkBMPImageIOFactory.h" | |||
#include "itkNRRDImageIOFactory.h" | |||
#include "./BridgeOpenCV/include/itkOpenCVImageBridge.h" | |||
/******************************************************** | |||
* @class : DataLoad | |||
* @brief : 构造函数 | |||
* @details : | |||
*********************************************************/ | |||
DataLoad::DataLoad() | |||
{ | |||
} | |||
DataLoad::~DataLoad() | |||
{ | |||
} | |||
/******************************************************** | |||
* @function : Init | |||
* @brief : 初始化 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
bool DataLoad::Init() | |||
{ | |||
//初始化的时候注册一些要用到的图像类别工厂,否则后面的读写操作无法成功 | |||
itk::GDCMImageIOFactory::RegisterOneFactory(); | |||
itk::NiftiImageIOFactory::RegisterOneFactory(); | |||
itk::PNGImageIOFactory::RegisterOneFactory(); | |||
itk::JPEGImageIOFactory::RegisterOneFactory(); | |||
itk::BMPImageIOFactory::RegisterOneFactory(); | |||
itk::NrrdImageIOFactory::RegisterOneFactory(); | |||
if (m_itkReader == nullptr) | |||
{ | |||
m_itkReader = SeriesReaderType::New(); | |||
} | |||
return true; | |||
} | |||
/******************************************************** | |||
* @function : GetHUValueImg | |||
* @brief : //获取原始图像的CT值图像 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
bool GetHUValueImg(cv::Mat& img, int nIntercept, int nSlope) | |||
{ | |||
if (!img.data) | |||
{ | |||
return false; | |||
} | |||
int rows(img.rows); | |||
int cols(img.cols); | |||
unsigned short* data = nullptr; | |||
/* | |||
首先,需要读取两个DICOM Tag信息,(0028|1052):rescale intercept和(0028|1053):rescale slope. | |||
然后通过公式: | |||
Hu = pixel * slope(1) + intercept(-1024) | |||
计算得到CT值。 | |||
*/ | |||
for (int i = 0; i < rows; ++i) | |||
{ | |||
data = img.ptr<unsigned short>(i); | |||
for (int j = 0; j < cols; ++j) | |||
{ | |||
int temp = data[j] * nSlope + nIntercept; | |||
if (temp < 0) | |||
{ | |||
temp = 0; | |||
} | |||
data[j] = temp; | |||
} | |||
} | |||
return true; | |||
} | |||
/* | |||
bool DataLoad::loadDcmImage(const QString &strImgPath, QImage &img, ImageHeaderInfo *pImageInfoStru) | |||
{ | |||
DcmFileFormat fileformat; | |||
OFCondition oc = fileformat.loadFile(strImgPath.toLocal8Bit().data()); //读取Dicom图像 | |||
if (!oc.good()) //判断Dicom文件是否读取成功 | |||
{ | |||
std::cout << "file Load error" << std::endl; | |||
return false; | |||
} | |||
DcmDataset *dataset = fileformat.getDataset(); //得到Dicom的数据集,所有的数据都存储在数据集当中 | |||
E_TransferSyntax xfer = dataset->getOriginalXfer(); //得到传输语法 | |||
unsigned short sImgWidth; //获取图像的窗宽高 | |||
unsigned short sImgHeight; | |||
dataset->findAndGetUint16(DCM_Rows, sImgHeight); | |||
dataset->findAndGetUint16(DCM_Columns, sImgWidth); | |||
int nIntercept(-1), nSlope(-1); | |||
OFString strIntercept, strSlope; | |||
dataset->findAndGetOFString(DCM_RescaleIntercept, strIntercept);//Intercept | |||
dataset->findAndGetOFString(DCM_RescaleSlope, strSlope);//Slope | |||
nIntercept = QString::fromLatin1(strIntercept.c_str()).toInt(); | |||
nSlope = QString::fromLatin1(strSlope.c_str()).toInt(); | |||
if (nullptr != pImageInfoStru) | |||
{ | |||
OFString stPatientName; | |||
dataset->findAndGetOFString(DCM_PatientName, stPatientName); //获取病人姓名 | |||
OFString strPatientAge; | |||
dataset->findAndGetOFString(DCM_PatientAge, strPatientAge); //获取病人年龄 | |||
OFString strPatientSex; | |||
dataset->findAndGetOFString(DCM_PatientSex, strPatientSex); //获取病人性别 | |||
unsigned short bit_count(0); | |||
dataset->findAndGetUint16(DCM_BitsStored, bit_count); //获取像素的位数 bit | |||
OFString isRGB; | |||
dataset->findAndGetOFString(DCM_PhotometricInterpretation, isRGB);//DCM图片的图像模式 | |||
unsigned short img_bits(0); | |||
dataset->findAndGetUint16(DCM_SamplesPerPixel, img_bits); //单个像素占用多少byte | |||
unsigned short sWinCenter, sWinWidth; //获取源图像中的窗位和窗宽 | |||
dataset->findAndGetUint16(DCM_WindowCenter, sWinCenter); | |||
dataset->findAndGetUint16(DCM_WindowWidth, sWinWidth); | |||
float fPixelSpacing; | |||
OFString strPixelSpacing; | |||
dataset->findAndGetOFString(DCM_PixelSpacing, strPixelSpacing);//DCM图片的图像模式 | |||
fPixelSpacing = QString::fromLatin1(strPixelSpacing.c_str()).toFloat(); | |||
pImageInfoStru->strPatientName = QString::fromLocal8Bit(stPatientName.c_str()); | |||
pImageInfoStru->strPatientAge = QString::fromLocal8Bit(strPatientAge.c_str()); | |||
pImageInfoStru->strPatientSex = QString::fromLocal8Bit(strPatientSex.c_str()); | |||
pImageInfoStru->nWidth = sImgWidth; | |||
pImageInfoStru->nHeight = sImgHeight; | |||
pImageInfoStru->fPixelSpacing = fPixelSpacing; | |||
pImageInfoStru->nIntercept = nIntercept; | |||
pImageInfoStru->nSlope = nSlope; | |||
} | |||
DcmElement* element = NULL; //读取dcm中的像素值 | |||
OFCondition result = dataset->findAndGetElement(DCM_PixelData, element); | |||
if (result.bad() || element == NULL) | |||
{ | |||
return false; | |||
} | |||
Uint16* pixData16; | |||
result = element->getUint16Array(pixData16); | |||
if (result.bad()) | |||
{ | |||
return false; | |||
} | |||
cv::Mat matImg(sImgWidth, sImgHeight, CV_16UC1, cv::Scalar::all(0)); | |||
unsigned short* data = nullptr; | |||
for (int i = 0; i < sImgHeight; i++) | |||
{ | |||
data = matImg.ptr<unsigned short>(i); //取得每一行的头指针 也可使用dst2.at<unsigned short>(i, j) = ? | |||
for (int j = 0; j < sImgWidth; j++) | |||
{ | |||
unsigned short temp = pixData16[i * 512 + j]; | |||
temp = temp == 63536 ? 0 : temp; | |||
*data++ = temp; | |||
} | |||
} | |||
GetHUValueImg(matImg, nIntercept, nSlope); | |||
matImg.convertTo(matImg, CV_8U); | |||
QImage img2Copy(matImg.data, sImgWidth, sImgHeight, matImg.step, QImage::Format_Grayscale8); | |||
img = img2Copy.copy(); | |||
if (img.isNull()) | |||
{ | |||
return false; | |||
} | |||
return true; | |||
} | |||
bool DataLoad::loadNoSuffixImage(const QString &strImgPath, QImage &img, ImageHeaderInfo *pImageInfoStru) | |||
{ | |||
//加载无后缀名的图片 | |||
//目前先认为是dcm | |||
return loadDcmImage(strImgPath, img, pImageInfoStru); | |||
} | |||
bool DataLoad::loadImage(const QString &strImgPath, QImage &img, ImageHeaderInfo *pImageInfoStru) | |||
{ | |||
//格式判断 | |||
QFileInfo fileInfo(strImgPath); | |||
if (fileInfo.suffix() == "dcm") | |||
{ | |||
return loadDcmImage(strImgPath, img, pImageInfoStru); | |||
} | |||
else if (fileInfo.suffix() == "") | |||
{ | |||
return loadNoSuffixImage(strImgPath, img, pImageInfoStru); | |||
} | |||
return true; | |||
} | |||
bool DataLoad::loadSingleImage(const QString &strFilePath, ImageInfoStru &stImageInfoStru) | |||
{ | |||
ImageHeaderInfo stImageHeaderInfo; | |||
QImage imgLoadTemp; | |||
bool bRet = loadImage(m_strCurFileOrDirPath, imgLoadTemp, &stImageHeaderInfo); | |||
stImageInfoStru.stImageHeaderInfo = stImageHeaderInfo; | |||
stImageInfoStru.vecImg.push_back(imgLoadTemp); | |||
return bRet; | |||
} | |||
bool DataLoad::loadImageFromDir(const QString &strDirPath, ImageInfoStru &stImageInfoStru) | |||
{ | |||
//判断路径是否存在 | |||
QDir dir(strDirPath); | |||
if (!dir.exists()) | |||
{ | |||
return false; | |||
} | |||
QStringList filters; | |||
//filters << QString("*.dcm"); | |||
dir.setFilter(QDir::Files | QDir::NoSymLinks); //设置类型过滤器,只为文件格式 | |||
dir.setNameFilters(filters); //设置文件名称过滤器,只为filters格式(后缀为.jpeg等图片格式) | |||
//获取分隔符 | |||
QChar separator = QChar('/'); | |||
if (!strDirPath.contains(separator)) | |||
{ | |||
separator = QChar('\\'); | |||
} | |||
QChar last_char = strDirPath.at(strDirPath.length() - 1); | |||
if (last_char == separator) | |||
{ | |||
separator = QChar(); | |||
} | |||
QStringList lstFilePath; | |||
foreach(QFileInfo mfi, dir.entryInfoList()) | |||
{ | |||
if (mfi.isFile() && (mfi.suffix() == "dcm" || mfi.suffix() == "")) | |||
{ | |||
QString file_path = strDirPath + separator + mfi.fileName(); | |||
lstFilePath.append(file_path); | |||
} | |||
} | |||
qSort(lstFilePath.begin(), lstFilePath.end(), [](const QString &s1, const QString &s2) { | |||
return s1.size() < s2.size() || (s1.size() == s2.size() && s1 < s2); | |||
}); | |||
bool bRet = false; | |||
for (int i = 0 ; i< lstFilePath.size();i++) | |||
{ | |||
QImage imgLoadTemp; | |||
if (i == 0) | |||
{ | |||
ImageHeaderInfo stImageHeaderInfo; | |||
bRet = loadImage(lstFilePath[i], imgLoadTemp, &stImageHeaderInfo); | |||
stImageInfoStru.stImageHeaderInfo = stImageHeaderInfo; | |||
} | |||
else | |||
{ | |||
bRet = loadImage(lstFilePath[i], imgLoadTemp); | |||
} | |||
if (!bRet) | |||
{ | |||
return false; | |||
} | |||
stImageInfoStru.vecImg.push_back(imgLoadTemp); | |||
} | |||
return true; | |||
} | |||
*/ | |||
/******************************************************** | |||
* @function : loadImageSeries | |||
* @brief : 加载图片序列 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
bool DataLoad::loadImageSeries(const QString &strDirPath, ImageHeaderInfo &stImageHeaderInfo) | |||
{ | |||
bool bRet = true; | |||
if (m_pItkDicomIO == nullptr) | |||
{ | |||
m_pItkDicomIO = itk::GDCMImageIO::New(); | |||
} | |||
// Get the DICOM filenames from the directory | |||
if (m_nameGenerator == nullptr) | |||
{ | |||
m_nameGenerator = itk::GDCMSeriesFileNames::New(); | |||
} | |||
m_nameGenerator->SetDirectory(strDirPath.toLocal8Bit().data()); | |||
try | |||
{ | |||
typedef std::vector<std::string> seriesIdContainer; | |||
const seriesIdContainer & seriesUID = m_nameGenerator->GetSeriesUIDs(); | |||
seriesIdContainer::const_iterator seriesItr = seriesUID.begin(); | |||
seriesIdContainer::const_iterator seriesEnd = seriesUID.end(); | |||
while (seriesItr != seriesEnd) | |||
{ | |||
seriesItr++; | |||
} | |||
typedef std::vector<std::string> fileNamesContainer; | |||
fileNamesContainer fileNames; | |||
fileNames = m_nameGenerator->GetFileNames(""); | |||
m_itkReader->SetFileNames(fileNames); | |||
m_itkReader->SetImageIO(m_pItkDicomIO); | |||
m_itkReader->UpdateLargestPossibleRegion(); | |||
try | |||
{ | |||
m_itkReader->Update(); | |||
} | |||
catch (itk::ExceptionObject &ex) | |||
{ | |||
std::string str(ex.what()); | |||
std::cout << ex; | |||
return false; | |||
} | |||
char* pParams = new char[256]; | |||
m_pItkDicomIO->GetPatientName(pParams); | |||
stImageHeaderInfo.strPatientName = pParams; | |||
memset(pParams, 0, 256); | |||
m_pItkDicomIO->GetPatientAge(pParams); | |||
stImageHeaderInfo.strPatientAge = pParams; | |||
memset(pParams, 0, 256); | |||
m_pItkDicomIO->GetPatientSex(pParams); | |||
stImageHeaderInfo.strPatientSex = pParams; | |||
memset(pParams, 0, 256); | |||
m_pItkDicomIO->GetModality(pParams); | |||
stImageHeaderInfo.strFileType = pParams; | |||
delete[] pParams; | |||
pParams = nullptr; | |||
std::string strWindowCenter; | |||
getValueFromTag(DCM_WindowCenter, strWindowCenter); | |||
std::string strWindowWidth; | |||
getValueFromTag(DCM_WindowWidth, strWindowWidth); | |||
std::string strSlope; | |||
getValueFromTag(DCM_RescaleSlope, strSlope); | |||
std::string strIntercept; | |||
getValueFromTag(DCM_RescaleIntercept, strIntercept); | |||
std::string strALinePixelSpacing; | |||
getValueFromTag(DCM_ALinePixelSpacing, strALinePixelSpacing); | |||
ImageType3D::PixelType maxValue, minValue; | |||
std::string strSmallestImagePixelValue; | |||
//getValueFromTag(DCM_SmallestImagePixelValue, strSmallestImagePixelValue); | |||
//minValue = std::atoi(strSmallestImagePixelValue.c_str()); | |||
std::string strLargestImagePixelValue; | |||
//getValueFromTag(DCM_LargestImagePixelValue, strLargestImagePixelValue); | |||
//maxValue = std::atoi(strLargestImagePixelValue.c_str()); | |||
double dS1 = m_pItkDicomIO->GetSpacing(SagittalPlane); | |||
double dS2 = m_pItkDicomIO->GetSpacing(CoronalPlane); | |||
double dS3 = m_pItkDicomIO->GetSpacing(TransversePlane); | |||
ImageType3D *img = m_itkReader->GetOutput(); | |||
itk::Size<3> sliceSize = img->GetLargestPossibleRegion().GetSize(); | |||
if (strSmallestImagePixelValue.empty() || strLargestImagePixelValue.empty()) | |||
{ | |||
typedef itk::MinimumMaximumImageCalculator <ImageType3D> IMinimumMaximumImageCalculatorType; | |||
IMinimumMaximumImageCalculatorType::Pointer imageCalculatorFilter = IMinimumMaximumImageCalculatorType::New(); | |||
imageCalculatorFilter->SetImage(img); | |||
imageCalculatorFilter->Compute(); | |||
maxValue = imageCalculatorFilter->GetMaximum(); //最大值 | |||
minValue = imageCalculatorFilter->GetMinimum(); //最小值 | |||
} | |||
stImageHeaderInfo.nWidth = sliceSize[SagittalPlane]; | |||
stImageHeaderInfo.nHeight = sliceSize[CoronalPlane]; | |||
stImageHeaderInfo.nThickNess = sliceSize[TransversePlane]; | |||
stImageHeaderInfo.strFilePath = strDirPath; | |||
stImageHeaderInfo.fPixelSpacingW = dS1; | |||
stImageHeaderInfo.fPixelSpacingH = dS2; | |||
stImageHeaderInfo.fPixelSpacingT = dS3; | |||
//stImageHeaderInfo.nWinCenter = std::atoi(strWindowCenter.c_str()); | |||
//stImageHeaderInfo.nWinWidth = std::atoi(strWindowWidth.c_str()); | |||
stImageHeaderInfo.nWinCenter = (maxValue + minValue) / 2; | |||
stImageHeaderInfo.nWinWidth = maxValue - minValue; | |||
stImageHeaderInfo.nSlope = std::atoi(strSlope.c_str()); | |||
stImageHeaderInfo.nIntercept = std::atoi(strIntercept.c_str()); | |||
ImageDataManager::getInstance()->setHeaderInfo(stImageHeaderInfo); | |||
ImageDataManager::getInstance()->setImageSerial(img); | |||
bRet = ImageDataManager::getInstance()->loadLabelInfo(strDirPath,IMAGE_TYPE::IMG_DCM); | |||
} | |||
catch (itk::ExceptionObject &ex) | |||
{ | |||
std::string str(ex.what()); | |||
std::cout << ex; | |||
return 0; | |||
} | |||
return bRet; | |||
} | |||
/******************************************************** | |||
* @function : loadNiiImage | |||
* @brief : 加载Nii图片 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
bool DataLoad::loadNiiImage(const QString &strDirPath, ImageHeaderInfo &stImageHeaderInfo) | |||
{ | |||
bool bRet = true; | |||
if (m_pItkNiiIO== nullptr) | |||
{ | |||
m_pItkNiiIO = itk::NiftiImageIO::New(); | |||
} | |||
try | |||
{ | |||
if (m_itkNiiReader == nullptr) | |||
{ | |||
m_itkNiiReader = itk::ImageFileReader<ImageType3D>::New(); | |||
} | |||
m_itkNiiReader->SetFileName(strDirPath.toLocal8Bit().data()); | |||
m_itkNiiReader->SetImageIO(m_pItkNiiIO); | |||
m_itkNiiReader->UpdateLargestPossibleRegion(); | |||
try | |||
{ | |||
m_itkNiiReader->Update(); | |||
} | |||
catch (itk::ExceptionObject &ex) | |||
{ | |||
std::string str(ex.what()); | |||
std::cout << ex; | |||
return false; | |||
} | |||
/*char* pParams = new char[256]; | |||
m_pItkNiiIO->GetPatientName(pParams); | |||
stImageHeaderInfo.strPatientName = pParams; | |||
memset(pParams, 0, 256); | |||
m_pItkNiiIO->GetPatientAge(pParams); | |||
stImageHeaderInfo.strPatientAge = pParams; | |||
memset(pParams, 0, 256); | |||
m_pItkNiiIO->GetPatientSex(pParams); | |||
stImageHeaderInfo.strPatientSex = pParams; | |||
delete[] pParams; | |||
pParams = nullptr; | |||
std::string strWindowCenter; | |||
getValueFromTag(DCM_WindowCenter, strWindowCenter); | |||
std::string strWindowWidth; | |||
getValueFromTag(DCM_WindowWidth, strWindowWidth); | |||
std::string strSlope; | |||
getValueFromTag(DCM_RescaleSlope, strSlope); | |||
std::string strIntercept; | |||
getValueFromTag(DCM_RescaleIntercept, strIntercept); | |||
std::string strALinePixelSpacing; | |||
getValueFromTag(DCM_ALinePixelSpacing, strALinePixelSpacing);*/ | |||
double dS1 = m_pItkNiiIO->GetSpacing(SagittalPlane); | |||
double dS2 = m_pItkNiiIO->GetSpacing(CoronalPlane); | |||
double dS3 = m_pItkNiiIO->GetSpacing(TransversePlane); | |||
ImageType3D *img = m_itkNiiReader->GetOutput(); | |||
itk::Size<3> sliceSize = img->GetLargestPossibleRegion().GetSize(); | |||
ImageType3D::PixelType pixelValue, maxValue, minValue; | |||
typedef itk::MinimumMaximumImageCalculator <ImageType3D> IMinimumMaximumImageCalculatorType; | |||
IMinimumMaximumImageCalculatorType::Pointer imageCalculatorFilter = IMinimumMaximumImageCalculatorType::New(); | |||
imageCalculatorFilter->SetImage(img); | |||
imageCalculatorFilter->Compute(); | |||
maxValue = imageCalculatorFilter->GetMaximum(); //最大值 | |||
minValue = imageCalculatorFilter->GetMinimum(); //最小值 | |||
stImageHeaderInfo.nWidth = sliceSize[SagittalPlane]; | |||
stImageHeaderInfo.nHeight = sliceSize[CoronalPlane]; | |||
stImageHeaderInfo.nThickNess = sliceSize[TransversePlane]; | |||
stImageHeaderInfo.strFilePath = strDirPath; | |||
stImageHeaderInfo.fPixelSpacingW = dS1; | |||
stImageHeaderInfo.fPixelSpacingH = dS2; | |||
stImageHeaderInfo.fPixelSpacingT = dS3; | |||
//stImageHeaderInfo.nWinCenter = std::atoi(strWindowCenter.c_str()); | |||
//stImageHeaderInfo.nWinWidth = std::atoi(strWindowWidth.c_str()); | |||
stImageHeaderInfo.nWinCenter = (maxValue + minValue) / 2; | |||
stImageHeaderInfo.nWinWidth = maxValue - minValue; | |||
/*stImageHeaderInfo.nSlope = std::atoi(strSlope.c_str()); | |||
stImageHeaderInfo.nIntercept = std::atoi(strIntercept.c_str());*/ | |||
ImageDataManager::getInstance()->setImageSerial(img); | |||
ImageDataManager::getInstance()->setHeaderInfo(stImageHeaderInfo); | |||
bRet = ImageDataManager::getInstance()->loadLabelInfo(strDirPath, IMAGE_TYPE::IMG_NII); | |||
} | |||
catch (itk::ExceptionObject &ex) | |||
{ | |||
std::string str(ex.what()); | |||
std::cout << ex; | |||
return 0; | |||
} | |||
return bRet; | |||
} | |||
/******************************************************** | |||
* @function : getValueFromTag | |||
* @brief : 根据tag获取值 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DataLoad::getValueFromTag(DcmTagKey keyTag, std::string& strValue) | |||
{ | |||
QString strTagSpacing(keyTag.toString().c_str()); | |||
strTagSpacing = strTagSpacing.mid(1, strTagSpacing.size() - 2); | |||
strTagSpacing.replace(',', '|'); | |||
m_pItkDicomIO->GetValueFromTag(strTagSpacing.toLocal8Bit().data(), strValue); | |||
} | |||
/******************************************************** | |||
* @function : startLoadData | |||
* @brief : 开启线程加载数据 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DataLoad::startLoadData(const QString &strPath) | |||
{ | |||
m_strCurFileOrDirPath = strPath; | |||
std::thread thrAnalysis(&DataLoad::run, this); | |||
if (thrAnalysis.joinable()) | |||
{ | |||
thrAnalysis.detach(); | |||
} | |||
} | |||
/******************************************************** | |||
* @function : run | |||
* @brief : 加载数据线程函数 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DataLoad::run() | |||
{ | |||
QFileInfo fileInfo(m_strCurFileOrDirPath); | |||
bool bRet = false; | |||
ImageHeaderInfo stImageHeaderInfo; | |||
//如果是文件 | |||
if (fileInfo.isFile()) | |||
{ | |||
if (fileInfo.completeSuffix() == "nii" | |||
||fileInfo.completeSuffix() == "nii.gz") | |||
{ | |||
bRet = loadNiiImage(m_strCurFileOrDirPath, stImageHeaderInfo); | |||
} | |||
//bRet = loadSingleImage(m_strCurFileOrDirPath, stImageHeaderInfo); | |||
} | |||
else if (fileInfo.isDir()) | |||
{ | |||
//bRet = loadImageFromDir(m_strCurFileOrDirPath,stImageInfoStru); | |||
bRet = loadImageSeries(m_strCurFileOrDirPath, stImageHeaderInfo); | |||
} | |||
emit sigDataLoadFinish(bRet); | |||
} |
@@ -0,0 +1,61 @@ | |||
/******************************************************** | |||
* @file : DataLoad.h | |||
* @brief : brief | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-7-9 | |||
*********************************************************/ | |||
#pragma once | |||
#include <QObject> | |||
#include <thread> | |||
#include <QImage> | |||
#include "GlobalDef.h" | |||
#include "ImageDataManager.h" | |||
#include "dcmtk/config/osconfig.h" | |||
#include "dcmtk/dcmdata/dctk.h" | |||
#include "itkGDCMSeriesFileNames.h" | |||
#include "itkGDCMImageIO.h" | |||
#include "itkImageFileReader.h" | |||
#include "itkNiftiImageIO.h" | |||
class DataLoad : public QObject | |||
{ | |||
Q_OBJECT | |||
public: | |||
DataLoad(); | |||
~DataLoad(); | |||
bool Init(); | |||
protected: | |||
//bool loadDcmImage(const QString &strImgPath, QImage &img, ImageHeaderInfo *pImageInfoStru = nullptr); | |||
//bool loadNoSuffixImage(const QString &strImgPath, QImage &img, ImageHeaderInfo *pImageInfoStru = nullptr); | |||
//bool loadImage(const QString &strImgPath, QImage &img, ImageHeaderInfo *pImageInfoStru = nullptr); | |||
//bool loadSingleImage(const QString &strFilePath, ImageInfoStru &stImageInfoStru); | |||
//bool loadImageFromDir(const QString &strDirPath, ImageInfoStru &stImageInfoStru); | |||
//加载图片序列 | |||
bool loadImageSeries(const QString &strDirPath, ImageHeaderInfo &stImageHeaderInfo); | |||
//加载Nii文件 | |||
bool loadNiiImage(const QString &strDirPath, ImageHeaderInfo &stImageHeaderInfo); | |||
//根据tag获取值 | |||
void getValueFromTag(DcmTagKey keyTag, std::string& strValue); | |||
public: | |||
//开始加载数据 | |||
void startLoadData(const QString &strPath); | |||
//线程处理函数 | |||
void run(); | |||
signals: | |||
void sigDataLoadFinish(bool bSuccess = true); | |||
private: | |||
QString m_strCurFileOrDirPath; //当前加载的文件或文件夹路径 | |||
SeriesReaderType::Pointer m_itkReader = nullptr; // 读文件句柄 | |||
itk::GDCMSeriesFileNames::Pointer m_nameGenerator =nullptr; //文件生成器 | |||
itk::GDCMImageIO::Pointer m_pItkDicomIO = nullptr; //文件io句柄 | |||
itk::ImageFileReader<ImageType3D>::Pointer m_itkNiiReader = nullptr; //nii文件读取句柄 | |||
itk::NiftiImageIO::Pointer m_pItkNiiIO = nullptr; //nii文件io句柄 | |||
}; |
@@ -0,0 +1,38 @@ | |||
/******************************************************** | |||
* @file : DrawBase.cpp | |||
* @brief : | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-5-8 | |||
*********************************************************/ | |||
#include "DrawBase.h" | |||
PEN_TYPE DrawBase::m_emPenType = PenNone; | |||
int DrawBase::m_nAlphaValue = 100; | |||
DrawBase::DrawBase() | |||
{ | |||
} | |||
DrawBase::~DrawBase() | |||
{ | |||
} | |||
PEN_TYPE DrawBase::getCurPenType() | |||
{ | |||
return m_emPenType; | |||
} | |||
void DrawBase::setCurPenType(PEN_TYPE emPenType) | |||
{ | |||
m_emPenType = emPenType; | |||
} | |||
void DrawBase::setAlphaValue(int nAlphaValue) | |||
{ | |||
m_nAlphaValue = nAlphaValue; | |||
} | |||
@@ -0,0 +1,89 @@ | |||
/******************************************************** | |||
* @file : DrawBase.h | |||
* @brief : | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-5-8 | |||
*********************************************************/ | |||
#pragma once | |||
#include <QObject> | |||
#include <QMouseEvent> | |||
#include <QPolygon> | |||
#include <QColor> | |||
#include <QLineF> | |||
#include "GlobalDef.h" | |||
#define SELECT_LINE_COLOR QColor(0,255,0) | |||
#define DRWAING_POINT_COLOR QColor(255,255,0) | |||
#define COMMON_POINT_LINE_COLOR QColor(255,255,0) | |||
//画笔类型 | |||
enum PEN_TYPE | |||
{ | |||
PenNone, | |||
PenPoint, | |||
PenPolygon, //多边形 | |||
PenDrawPen, //画笔 | |||
MeasureRuler, | |||
MeasurePolygon, | |||
MeasureCircle, | |||
MeasureOval, | |||
}; | |||
class ExLineF :public QLineF | |||
{ | |||
public: | |||
std::string strTargetName; | |||
}; | |||
class ExPolygonF :public QPolygonF | |||
{ | |||
public: | |||
std::string strTargetName; | |||
std::string strTargetDisc; | |||
int nTargetID; | |||
int nTargetType = PenPolygon; | |||
bool bClosed = false; //是否已封闭 | |||
bool bIsSelected = false; //是否被选中 | |||
int nSelectPoint = -1; //当前被选中的点 | |||
QVector<int> lstValue; //存所有valve值 | |||
void reset() | |||
{ | |||
strTargetName = ""; | |||
strTargetDisc = ""; | |||
nTargetID = -1; | |||
bClosed = false; | |||
bIsSelected = false; | |||
nSelectPoint = -1; | |||
this->clear(); | |||
lstValue.clear(); | |||
} | |||
}; | |||
class DrawBase : public QObject | |||
{ | |||
Q_OBJECT | |||
public: | |||
DrawBase(); | |||
~DrawBase(); | |||
//virtual bool initDraw(); | |||
PEN_TYPE getCurPenType(); | |||
static void setCurPenType(PEN_TYPE emPenType); | |||
static void setAlphaValue(int nAlphaValue); | |||
//virtual void mousePressEvent(QMouseEvent *event); | |||
//virtual void mouseMoveEvent(QMouseEvent *event); | |||
//virtual void mouseReleaseEvent(QMouseEvent *event); | |||
//virtual void resizeEvent(QResizeEvent *event); | |||
protected: | |||
virtual void DrawGraphics() = 0; | |||
protected: | |||
static PEN_TYPE m_emPenType; //画笔类型 | |||
static int m_nAlphaValue; //透明度 | |||
QColor m_Color; //画笔颜色 | |||
int m_nSize; //画笔宽度 | |||
ImageHeaderInfo m_stImageHeaderInfo; //图片序列头信息 | |||
bool m_bIsDrawing = false; | |||
bool m_bIsMoving = false; | |||
}; |
@@ -0,0 +1,817 @@ | |||
/******************************************************** | |||
* @file : DrawPen.cpp | |||
* @brief : | |||
* @details : | |||
* @author : qh.zhang@atisz.ac.cn | |||
* @date : 2019-7-3 | |||
*********************************************************/ | |||
#include <QPainter> | |||
#include <QDebug> | |||
#include <QTime> | |||
#include "DrawPen.h" | |||
#include "ImageDataManager.h" | |||
#include "AllSettings.h" | |||
class ImageWidget; | |||
#define POINT_RADIUS 2 | |||
#define LINE_WIDTH 2 | |||
#define POINT_LINE_WIDTH 1 | |||
#define POINT_SELECT_RADIUS 3 | |||
#define DRAWPEN_POINT_COUNTS_LIMIT 20 | |||
INTERP_METHOD DrawPen::m_emInterpMethod = IM_None; | |||
QPair<VIEW_PLANE, int> DrawPen::m_pairSelectTarget = qMakePair(VIEW_PLANE::CoronalPlane,-1); | |||
/******************************************************** | |||
* @function : DrawPen | |||
* @brief : 构造函数 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
DrawPen::DrawPen(QWidget *parent) | |||
:m_pParent(parent) | |||
{ | |||
} | |||
DrawPen::~DrawPen() | |||
{ | |||
} | |||
/******************************************************** | |||
* @function : initDraw | |||
* @brief : 初始化 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
bool DrawPen::initDraw(VIEW_PLANE emPlane) | |||
{ | |||
m_emPlane = emPlane; | |||
return true; | |||
} | |||
/******************************************************** | |||
* @function : setImgPointer | |||
* @brief : 设置传入的图片指针 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::setImgPointer(QImage *pImgSrc, QImage *pImgDrawing) | |||
{ | |||
m_pImgSrc = pImgSrc; | |||
m_pImgDrawing = pImgDrawing; | |||
} | |||
/******************************************************** | |||
* @function : setCross | |||
* @brief : 设置十字光标位置 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::setCross(QPointF ptCross) | |||
{ | |||
m_ptCross = ptCross; | |||
//DrawGraphics(); | |||
} | |||
/******************************************************** | |||
* @function : setZoom | |||
* @brief : 设置缩放值 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::setZoom(float fZoom) | |||
{ | |||
m_fZoom = fZoom; | |||
//DrawGraphics(); | |||
} | |||
/******************************************************** | |||
* @function : reload | |||
* @brief : 重新加载图片 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::reload(int nIndex) | |||
{ | |||
m_nCurFrameIndex = nIndex; | |||
std::map<int, LabelAnalysis::Target> mapTargetsTmp; | |||
ImageDataManager::getInstance()->getLabelInfo(m_emPlane, m_nCurFrameIndex, mapTargetsTmp); | |||
m_stImageHeaderInfo = ImageDataManager::getInstance()->getImageHeaderInfo(); | |||
m_mapTargets.clear(); | |||
for each (auto var in mapTargetsTmp) | |||
{ | |||
ExPolygonF poly; | |||
for each (auto ptF in var.second.lstVertex) | |||
{ | |||
poly.append(QPointF(ptF.fX,ptF.fY)); | |||
} | |||
poly.bClosed = true; | |||
poly.strTargetName = var.second.strTargetName; | |||
m_mapTargets[var.first] = poly; | |||
} | |||
m_pairCurTarget.second.reset(); | |||
m_bIsDrawing = false; | |||
m_bIsMoving = false; | |||
emit sigSelectPolygon(QSize(0, 0)); | |||
//m_pairSelectTarget = qMakePair(VIEW_PLANE::CoronalPlane, -1); | |||
//DrawGraphics(); | |||
} | |||
/******************************************************** | |||
* @function : delTarget | |||
* @brief : 删除选中目标 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::delTarget(int nIndex) | |||
{ | |||
if (m_mapTargets.find(nIndex)!=m_mapTargets.end()) | |||
{ | |||
m_mapTargets.erase(nIndex); | |||
} | |||
ImageDataManager::getInstance()->updateLabelInfo(m_emPlane, m_nCurFrameIndex, m_mapTargets); | |||
m_pairSelectTarget = qMakePair(VIEW_PLANE::CoronalPlane, -1); | |||
emit sigSelectPolygon(QSize(0, 0)); | |||
} | |||
/******************************************************** | |||
* @function : clearTargets | |||
* @brief : 删除当前页面的目标 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::clearTargets() | |||
{ | |||
m_mapTargets.clear(); | |||
m_pairSelectTarget = qMakePair(VIEW_PLANE::CoronalPlane, -1); | |||
emit sigSelectPolygon(QSize(0,0)); | |||
ImageDataManager::getInstance()->updateLabelInfo(m_emPlane, m_nCurFrameIndex, m_mapTargets); | |||
} | |||
/******************************************************** | |||
* @function : mousePressEvent | |||
* @brief : 鼠标按下事件 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::mousePressEvent(QMouseEvent *event, QPointF ptF, int nValue) | |||
{ | |||
//如果没有在绘图,判断是否选择了点或者目标 | |||
if ((event->buttons() & Qt::LeftButton) == Qt::LeftButton) | |||
{ | |||
if (!m_bIsDrawing) | |||
{ | |||
checkSelect(ptF); | |||
} | |||
//判断是否选中了某个目标 | |||
if (m_pairSelectTarget.first == m_emPlane | |||
&& m_pairSelectTarget.second != -1) | |||
{ | |||
//选中点,进入点移动模式 | |||
m_bIsMoving = true; | |||
m_ptfMoveLastPos = ptF; | |||
m_pParent->setCursor(Qt::ClosedHandCursor); //范围之外变回原来形状 | |||
} | |||
else | |||
{ | |||
m_bIsMoving = false; | |||
} | |||
} | |||
m_ptCross = ptF; | |||
switch (m_emPenType) | |||
{ | |||
case PenNone: | |||
//DrawGraphics(); | |||
break; | |||
case PenPoint: | |||
break; | |||
case PenPolygon: | |||
case PenDrawPen: | |||
if ((event->buttons() & Qt::LeftButton) == Qt::LeftButton) | |||
{ | |||
//判断是否选中了某个目标 | |||
if (m_bIsMoving) | |||
{ | |||
//do nothing | |||
} | |||
else | |||
{ | |||
while (1) | |||
{ | |||
if (m_pairCurTarget.second.size() == 0 | |||
&& m_mapTargets.find(m_pairCurTarget.first) != m_mapTargets.end()) | |||
{ | |||
++m_pairCurTarget.first; | |||
} | |||
else | |||
{ | |||
break; | |||
} | |||
} | |||
if (m_pairCurTarget.second.size()==0) | |||
{ | |||
QString strCurLabel; | |||
AllSettings::getInstance()->GetCurLabelAndColor(strCurLabel, m_Color); | |||
m_pairCurTarget.second.strTargetName = strCurLabel.toLocal8Bit().data(); | |||
} | |||
m_pairCurTarget.second.append(ptF); | |||
m_pairCurTarget.second.lstValue.append(nValue); | |||
m_bIsDrawing = true; | |||
} | |||
} | |||
else if ((event->buttons() & Qt::RightButton) == Qt::RightButton) | |||
{ | |||
m_bIsDrawing = false; | |||
if (m_pairCurTarget.second.size() <= 2) | |||
{ | |||
m_pairCurTarget.second.reset(); | |||
return; | |||
} | |||
//插值一下 | |||
generateInterpolationPoints(m_pairCurTarget.second); | |||
m_pairCurTarget.second.bClosed = true; | |||
m_pairCurTarget.second.nTargetID = m_pairCurTarget.first; | |||
m_mapTargets.insert(m_pairCurTarget); | |||
ImageDataManager::getInstance()->updateLabelInfo(m_emPlane, m_nCurFrameIndex, m_mapTargets); | |||
m_pairCurTarget.second.reset(); | |||
} | |||
//DrawGraphics(); | |||
break; | |||
case MeasureRuler: | |||
break; | |||
case MeasurePolygon: | |||
break; | |||
case MeasureCircle: | |||
break; | |||
case MeasureOval: | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
/******************************************************** | |||
* @function : mouseMoveEvent | |||
* @brief : 鼠标移动事件 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::mouseMoveEvent(QMouseEvent *event, QPointF ptF, int nValue) | |||
{ | |||
if (m_bIsDrawing) | |||
{ | |||
switch (m_emPenType) | |||
{ | |||
case PenNone: | |||
break; | |||
case PenPoint: | |||
break; | |||
case PenPolygon: | |||
break; | |||
case PenDrawPen: | |||
if ((event->buttons() & Qt::LeftButton) == Qt::LeftButton) | |||
{ | |||
if (m_bIsDrawing) | |||
{ | |||
m_pairCurTarget.second.append(ptF); | |||
m_pairCurTarget.second.lstValue.append(nValue); | |||
//qDebug() << ptF; | |||
//DrawGraphics(); | |||
} | |||
} | |||
break; | |||
case MeasureRuler: | |||
break; | |||
case MeasurePolygon: | |||
break; | |||
case MeasureCircle: | |||
break; | |||
case MeasureOval: | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
else if (m_bIsMoving) | |||
{ | |||
if ((event->buttons() & Qt::LeftButton) == Qt::LeftButton | |||
&& m_pairSelectTarget.first == m_emPlane | |||
&& m_pairSelectTarget.second != -1 | |||
) | |||
{ | |||
QPointF ptfDist = ptF - m_ptfMoveLastPos;//位移 | |||
m_ptfMoveLastPos = ptF; | |||
ExPolygonF& poly = m_mapTargets[m_pairSelectTarget.second]; | |||
if (poly.nSelectPoint!=-1) | |||
{ | |||
poly[poly.nSelectPoint] = poly[poly.nSelectPoint] + ptfDist; | |||
} | |||
else | |||
{ | |||
ExPolygonF polyTemp = poly; | |||
for (int i = 0; i < poly.size(); i++) | |||
{ | |||
polyTemp[i] = poly[i] + ptfDist; | |||
if (polyTemp[i].rx() > 1 | |||
|| polyTemp[i].ry() > 1 | |||
|| polyTemp[i].rx() < 0 | |||
|| polyTemp[i].ry() < 0 | |||
) | |||
{ | |||
return; | |||
} | |||
} | |||
poly = polyTemp; | |||
} | |||
} | |||
ImageDataManager::getInstance()->updateLabelInfo(m_emPlane, m_nCurFrameIndex, m_mapTargets); | |||
} | |||
else | |||
{ | |||
m_ptCross = ptF; | |||
} | |||
} | |||
/******************************************************** | |||
* @function : mouseReleaseEvent | |||
* @brief : 鼠标释放事件 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::mouseReleaseEvent(QMouseEvent *event, QPointF ptF, int nValue) | |||
{ | |||
m_bIsMoving = false; | |||
switch (m_emPenType) | |||
{ | |||
case PenNone: | |||
break; | |||
case PenPoint: | |||
break; | |||
case PenPolygon: | |||
break; | |||
case PenDrawPen: | |||
break; | |||
case MeasureRuler: | |||
break; | |||
case MeasurePolygon: | |||
break; | |||
case MeasureCircle: | |||
break; | |||
case MeasureOval: | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
/******************************************************** | |||
* @function : resizeEvent | |||
* @brief : | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::resizeEvent(QResizeEvent *event) | |||
{ | |||
//需要调整尺寸, 并且重新绘制 | |||
//DrawGraphics(); | |||
} | |||
/******************************************************** | |||
* @function : wheelEvent | |||
* @brief : brief | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::wheelEvent(QWheelEvent *event) | |||
{ | |||
//需要调整尺寸, 并且重新绘制 | |||
//DrawGraphics(); | |||
} | |||
/******************************************************** | |||
* @function : DrawGraphics | |||
* @brief : 整个画面绘制 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::DrawGraphics() | |||
{ | |||
QList<ExLineF> lstWTargets; | |||
QList<ExLineF> lstHTargets; | |||
ImageDataManager::getInstance()->getOtherPlaneTargetWH(m_emPlane, lstWTargets, lstHTargets, m_nCurFrameIndex); | |||
QPainter painter; | |||
QTime atime; | |||
*m_pImgDrawing = m_pImgSrc->convertToFormat(QImage::Format_RGB32); | |||
*m_pImgDrawing = m_pImgDrawing->scaled(m_pImgSrc->size()*m_fZoom, Qt::KeepAspectRatio); | |||
//设置画笔画刷 | |||
QPen penCommonLine; | |||
QBrush brushNone; | |||
penCommonLine.setColor(Qt::red); //改变颜色 | |||
penCommonLine.setWidth(LINE_WIDTH); | |||
QPen penCommenPoint; | |||
penCommenPoint.setColor(COMMON_POINT_LINE_COLOR); //改变颜色 | |||
penCommenPoint.setWidth(POINT_LINE_WIDTH); | |||
//正在绘制的画笔 | |||
QPen penDrawingLine; | |||
penDrawingLine.setColor(m_Color); | |||
penDrawingLine.setWidth(LINE_WIDTH); | |||
QPen penDrawingPoint; | |||
penDrawingPoint.setColor(DRWAING_POINT_COLOR); | |||
penDrawingPoint.setWidth(POINT_RADIUS); | |||
QBrush brushDrawingPoint(Qt::red); | |||
QPen penSelectLine; | |||
penSelectLine.setColor(SELECT_LINE_COLOR); | |||
penSelectLine.setWidth(LINE_WIDTH); | |||
painter.begin(m_pImgDrawing); | |||
for each (auto var in lstWTargets) | |||
{ | |||
QColor clrCurTgt = AllSettings::getInstance()->GetColorByLabel(QString::fromLocal8Bit(var.strTargetName.c_str())); | |||
clrCurTgt.setAlpha(m_nAlphaValue); | |||
painter.setPen(QPen(clrCurTgt)); | |||
QColor clrCurTgtBrush = clrCurTgt; | |||
clrCurTgtBrush.setAlpha(m_nAlphaValue); | |||
painter.setBrush(clrCurTgtBrush); | |||
drawLayer(&painter, var.p1(), var.p2()); | |||
} | |||
for each (auto var in lstHTargets) | |||
{ | |||
QColor clrCurTgt = AllSettings::getInstance()->GetColorByLabel(QString::fromLocal8Bit(var.strTargetName.c_str())); | |||
clrCurTgt.setAlpha(m_nAlphaValue); | |||
painter.setPen(QPen(clrCurTgt)); | |||
QColor clrCurTgtBrush = clrCurTgt; | |||
clrCurTgtBrush.setAlpha(m_nAlphaValue); | |||
painter.setBrush(clrCurTgtBrush); | |||
drawLayer(&painter, var.p1(), var.p2()); | |||
} | |||
//绘制已完成的图形 | |||
for each (auto varShape in m_mapTargets) | |||
{ | |||
QColor clrCurTgt = AllSettings::getInstance()->GetColorByLabel(QString::fromLocal8Bit(varShape.second.strTargetName.c_str())); | |||
QColor clrCurTgtBrush = clrCurTgt; | |||
clrCurTgtBrush.setAlpha(m_nAlphaValue); | |||
penCommonLine.setColor(clrCurTgt); | |||
//绘图 | |||
painter.setPen(penCommonLine); | |||
painter.setBrush(clrCurTgtBrush); | |||
//当前选中框 | |||
if (m_pairSelectTarget.first == m_emPlane | |||
&&m_pairSelectTarget.second == varShape.first) | |||
{ | |||
painter.setPen(penSelectLine); | |||
painter.setBrush(brushNone); | |||
drawPolygon(&painter, varShape.second,true); | |||
} | |||
else | |||
{ | |||
drawPolygon(&painter, varShape.second); | |||
} | |||
//绘点 | |||
if (varShape.second.size() < DRAWPEN_POINT_COUNTS_LIMIT) | |||
{ | |||
for (int i = 0; i < varShape.second.size(); i++) | |||
{ | |||
if (varShape.second.nSelectPoint == i) | |||
{ | |||
painter.setPen(penDrawingPoint); | |||
painter.setBrush(brushDrawingPoint); | |||
} | |||
else | |||
{ | |||
painter.setPen(penCommenPoint); | |||
} | |||
//painter.drawEllipse(QPoint(varShape.second[i].rx()*m_pImgDrawing->width(), varShape.second[i].ry()*m_pImgDrawing->height()), POINT_RADIUS, POINT_RADIUS); | |||
drawPoint(&painter, varShape.second[i]); | |||
} | |||
} | |||
} | |||
//绘制正在绘制的图形 | |||
//绘图 | |||
painter.setPen(penDrawingLine); | |||
drawPolygon(&painter, m_pairCurTarget.second); | |||
painter.setPen(penDrawingPoint); | |||
painter.setBrush(brushDrawingPoint); | |||
if (m_pairCurTarget.second.size()< DRAWPEN_POINT_COUNTS_LIMIT) | |||
{ | |||
//绘点 | |||
for (int i = 0; i < m_pairCurTarget.second.size(); i++) | |||
{ | |||
drawPoint(&painter, m_pairCurTarget.second[i]); | |||
} | |||
} | |||
//画十字 | |||
{ | |||
painter.setPen(QPen(QBrush(WIDGET_CROSS_COLOR), 1, Qt::DashDotLine));//设置画刷形式,背景色 | |||
drawLine(&painter, QPointF(0.0f, m_ptCross.ry()), QPointF(1.0f, m_ptCross.ry())); | |||
drawLine(&painter, QPointF(m_ptCross.rx(), 0), QPointF(m_ptCross.rx(), 1.0f)); | |||
} | |||
painter.end(); | |||
} | |||
/******************************************************** | |||
* @function : drawPoint | |||
* @brief : 画点 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::drawPoint(QPainter *p, QPointF pt) | |||
{ | |||
if (m_emPlane != TransversePlane) | |||
{ | |||
pt = QPointF(pt.rx(), 1.0f - pt.ry()); | |||
} | |||
p->drawEllipse(QPoint(pt.rx()*m_pImgDrawing->width(), pt.ry()*m_pImgDrawing->height()), POINT_RADIUS, POINT_RADIUS); | |||
} | |||
/******************************************************** | |||
* @function : drawLine | |||
* @brief : 画线 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::drawLine(QPainter *p, QPointF pt1, QPointF pt2) | |||
{ | |||
if (m_emPlane != TransversePlane) | |||
{ | |||
pt1 = QPointF(pt1.rx(), 1.0f - pt1.ry()); | |||
pt2 = QPointF(pt2.rx(), 1.0f - pt2.ry()); | |||
} | |||
p->drawLine(QPoint(round(pt1.rx()*m_pImgDrawing->width()), round(pt1.ry()*m_pImgDrawing->height())), | |||
QPoint(round(pt2.rx()*m_pImgDrawing->width()), round(pt2.ry()*m_pImgDrawing->height()))); | |||
} | |||
/******************************************************** | |||
* @function : drawLayer | |||
* @brief : 绘制透视出来的图层 | |||
* @input : | |||
* @output : | |||
* @return : | |||
*********************************************************/ | |||
void DrawPen::drawLayer(QPainter *p, QPointF pt1, QPointF pt2) | |||
{ | |||
if (m_emPlane != TransversePlane) | |||
{ | |||
pt1 = QPointF(pt1.rx(), 1.0f - pt1.ry()); | |||
pt2 = QPointF(pt2.rx(), 1.0f - pt2.ry()); | |||
} | |||
QRect rect; | |||
float fSpacing = m_stImageHeaderInfo.fPixelSpacingT/ m_stImageHeaderInfo.fPixelSpacingW; | |||