Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ModelZoo
RetinaFace_migraphx
Commits
906376c1
Commit
906376c1
authored
Nov 15, 2023
by
liucong
Browse files
重新进行Cpp代码的格式化
parent
474298d4
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1461 additions
and
1358 deletions
+1461
-1358
Src/RetinaFace.cpp
Src/RetinaFace.cpp
+594
-546
Src/RetinaFace.h
Src/RetinaFace.h
+31
-18
Src/Utility/CommonDefinition.h
Src/Utility/CommonDefinition.h
+16
-17
Src/Utility/CommonUtility.cpp
Src/Utility/CommonUtility.cpp
+14
-12
Src/Utility/CommonUtility.h
Src/Utility/CommonUtility.h
+4
-4
Src/Utility/Filesystem.cpp
Src/Utility/Filesystem.cpp
+576
-570
Src/Utility/Filesystem.h
Src/Utility/Filesystem.h
+27
-19
Src/Utility/SSDDefinition.h
Src/Utility/SSDDefinition.h
+44
-42
Src/Utility/SimpleLog.h
Src/Utility/SimpleLog.h
+136
-117
Src/main.cpp
Src/main.cpp
+19
-13
No files found.
Src/RetinaFace.cpp
View file @
906376c1
This diff is collapsed.
Click to expand it.
Src/RetinaFace.h
View file @
906376c1
...
@@ -10,34 +10,49 @@ namespace migraphxSamples
...
@@ -10,34 +10,49 @@ namespace migraphxSamples
class
DetectorRetinaFace
class
DetectorRetinaFace
{
{
public:
public:
DetectorRetinaFace
();
DetectorRetinaFace
();
~
DetectorRetinaFace
();
~
DetectorRetinaFace
();
ErrorCode
Initialize
(
InitializationParameterOfDetector
initializationParameterOfDetector
);
ErrorCode
Initialize
(
InitializationParameterOfDetector
initializationParameterOfDetector
);
ErrorCode
Detect
(
const
cv
::
Mat
&
srcImage
,
std
::
vector
<
ResultOfDetection
>
&
resultsOfDetection
);
ErrorCode
Detect
(
const
cv
::
Mat
&
srcImage
,
std
::
vector
<
ResultOfDetection
>&
resultsOfDetection
);
private:
private:
void
GetSSDParameter
();
void
GetSSDParameter
();
void
GetResult
(
const
std
::
vector
<
std
::
vector
<
float
>>
&
classification
,
const
std
::
vector
<
std
::
vector
<
float
>>
&
regression
,
std
::
vector
<
ResultOfDetection
>
&
resultsOfDetection
);
void
GetResult
(
const
std
::
vector
<
std
::
vector
<
float
>>&
classification
,
const
std
::
vector
<
std
::
vector
<
float
>>&
regression
,
std
::
vector
<
ResultOfDetection
>&
resultsOfDetection
);
std
::
vector
<
float
>
PermuteLayer
(
const
std
::
vector
<
float
>
&
data
,
int
width
,
int
height
,
int
channels
);
std
::
vector
<
float
>
void
PriorBoxLayer
(
int
indexOfLayer
,
int
*
priorboxOutputData
);
PermuteLayer
(
const
std
::
vector
<
float
>&
data
,
int
width
,
int
height
,
int
channels
);
void
SoftmaxLayer
(
int
softMaxWidth
[],
int
*
softMaxInputData
[],
int
*
softMaxOutputData
);
void
PriorBoxLayer
(
int
indexOfLayer
,
int
*
priorboxOutputData
);
void
DetectionOutputLayer
(
int
*
allLocPreds
[],
int
*
allPriorBoxes
[],
int
*
confScores
,
int
*
assistMemPool
);
void
SoftmaxLayer
(
int
softMaxWidth
[],
int
*
softMaxInputData
[],
int
*
softMaxOutputData
);
void
DetectionOutputLayer
(
int
*
allLocPreds
[],
int
*
allPriorBoxes
[],
int
*
confScores
,
int
*
assistMemPool
);
void
ComputeSoftMax
(
int
*
src
,
int
size
,
int
*
dst
);
void
ComputeSoftMax
(
int
*
src
,
int
size
,
int
*
dst
);
void
QuickSort
(
int
*
src
,
int
low
,
int
high
,
QuickSortStack
*
stack
,
int
maxNum
);
void
QuickSort
(
int
*
src
,
int
low
,
int
high
,
QuickSortStack
*
stack
,
int
maxNum
);
void
NonMaxSuppression
(
int
*
proposals
,
int
anchorsNum
,
int
NMSThresh
,
int
maxRoiNum
);
void
NonMaxSuppression
(
int
*
proposals
,
int
anchorsNum
,
int
NMSThresh
,
int
maxRoiNum
);
void
Swap
(
int
*
src1
,
int
*
src2
);
void
Swap
(
int
*
src1
,
int
*
src2
);
void
ComputeOverlap
(
int
xMin1
,
int
yMin1
,
int
xMax1
,
int
yMax1
,
int
xMin2
,
int
yMin2
,
int
xMax2
,
int
yMax2
,
int
*
areaSum
,
int
*
areaInter
);
void
ComputeOverlap
(
int
xMin1
,
void
CreateDetectionResults
(
std
::
vector
<
ResultOfDetection
>
&
resultsOfDetection
);
int
yMin1
,
int
xMax1
,
int
yMax1
,
int
xMin2
,
int
yMin2
,
int
xMax2
,
int
yMax2
,
int
*
areaSum
,
int
*
areaInter
);
void
CreateDetectionResults
(
std
::
vector
<
ResultOfDetection
>&
resultsOfDetection
);
private:
private:
cv
::
FileStorage
configurationFile
;
cv
::
FileStorage
configurationFile
;
migraphx
::
program
net
;
migraphx
::
program
net
;
cv
::
Size
inputSize
;
cv
::
Size
inputSize
;
std
::
string
inputName
;
std
::
string
inputName
;
...
@@ -51,10 +66,8 @@ private:
...
@@ -51,10 +66,8 @@ private:
bool
useFP16
;
bool
useFP16
;
SSDParameter
ssdParameter
;
SSDParameter
ssdParameter
;
};
};
}
}
// namespace migraphxSamples
#endif
#endif
Src/Utility/CommonDefinition.h
View file @
906376c1
...
@@ -7,33 +7,33 @@
...
@@ -7,33 +7,33 @@
namespace
migraphxSamples
namespace
migraphxSamples
{
{
// 路径分隔符(Linux:‘/’,Windows:’\\’)
// 路径分隔符(Linux:‘/’,Windows:’\\’)
#ifdef _WIN32
#ifdef _WIN32
#define
PATH_SEPARATOR '\\'
#define PATH_SEPARATOR '\\'
#else
#else
#define
PATH_SEPARATOR '/'
#define PATH_SEPARATOR '/'
#endif
#endif
#define CONFIG_FILE
"../Resource/Configuration.xml"
#define CONFIG_FILE "../Resource/Configuration.xml"
typedef
enum
_ErrorCode
typedef
enum
_ErrorCode
{
{
SUCCESS
=
0
,
// 0
SUCCESS
=
0
,
// 0
MODEL_NOT_EXIST
,
// 模型不存在
MODEL_NOT_EXIST
,
// 模型不存在
CONFIG_FILE_NOT_EXIST
,
// 配置文件不存在
CONFIG_FILE_NOT_EXIST
,
// 配置文件不存在
FAIL_TO_LOAD_MODEL
,
// 加载模型失败
FAIL_TO_LOAD_MODEL
,
// 加载模型失败
FAIL_TO_OPEN_CONFIG_FILE
,
// 加载配置文件失败
FAIL_TO_OPEN_CONFIG_FILE
,
// 加载配置文件失败
IMAGE_ERROR
,
// 图像错误
IMAGE_ERROR
,
// 图像错误
}
ErrorCode
;
}
ErrorCode
;
typedef
struct
_ResultOfPrediction
typedef
struct
_ResultOfPrediction
{
{
float
confidence
;
float
confidence
;
int
label
;
int
label
;
_ResultOfPrediction
()
:
confidence
(
0.0
f
),
label
(
0
){}
_ResultOfPrediction
()
:
confidence
(
0.0
f
),
label
(
0
)
{}
}
ResultOfPrediction
;
}
ResultOfPrediction
;
typedef
struct
_ResultOfDetection
typedef
struct
_ResultOfDetection
{
{
...
@@ -43,17 +43,16 @@ typedef struct _ResultOfDetection
...
@@ -43,17 +43,16 @@ typedef struct _ResultOfDetection
std
::
string
className
;
std
::
string
className
;
bool
exist
;
bool
exist
;
_ResultOfDetection
()
:
confidence
(
0.0
f
),
classID
(
0
),
exist
(
true
){}
_ResultOfDetection
()
:
confidence
(
0.0
f
),
classID
(
0
),
exist
(
true
)
{}
}
ResultOfDetection
;
}
ResultOfDetection
;
typedef
struct
_InitializationParameterOfDetector
typedef
struct
_InitializationParameterOfDetector
{
{
std
::
string
parentPath
;
std
::
string
parentPath
;
std
::
string
configFilePath
;
std
::
string
configFilePath
;
}
InitializationParameterOfDetector
;
}
InitializationParameterOfDetector
;
}
}
// namespace migraphxSamples
#endif
#endif
Src/Utility/CommonUtility.cpp
View file @
906376c1
...
@@ -3,34 +3,37 @@
...
@@ -3,34 +3,37 @@
namespace
migraphxSamples
namespace
migraphxSamples
{
{
bool
CompareConfidence
(
const
ResultOfDetection
&
L
,
const
ResultOfDetection
&
R
)
bool
CompareConfidence
(
const
ResultOfDetection
&
L
,
const
ResultOfDetection
&
R
)
{
{
return
L
.
confidence
>
R
.
confidence
;
return
L
.
confidence
>
R
.
confidence
;
}
}
bool
CompareArea
(
const
ResultOfDetection
&
L
,
const
ResultOfDetection
&
R
)
bool
CompareArea
(
const
ResultOfDetection
&
L
,
const
ResultOfDetection
&
R
)
{
{
return
L
.
boundingBox
.
area
()
>
R
.
boundingBox
.
area
();
return
L
.
boundingBox
.
area
()
>
R
.
boundingBox
.
area
();
}
}
void
NMS
(
std
::
vector
<
ResultOfDetection
>
&
detections
,
float
IOUThreshold
)
void
NMS
(
std
::
vector
<
ResultOfDetection
>&
detections
,
float
IOUThreshold
)
{
{
// sort
// sort
std
::
sort
(
detections
.
begin
(),
detections
.
end
(),
CompareConfidence
);
std
::
sort
(
detections
.
begin
(),
detections
.
end
(),
CompareConfidence
);
for
(
int
i
=
0
;
i
<
detections
.
size
();
++
i
)
for
(
int
i
=
0
;
i
<
detections
.
size
();
++
i
)
{
{
if
(
detections
[
i
].
exist
)
if
(
detections
[
i
].
exist
)
{
{
for
(
int
j
=
i
+
1
;
j
<
detections
.
size
();
++
j
)
for
(
int
j
=
i
+
1
;
j
<
detections
.
size
();
++
j
)
{
{
if
(
detections
[
j
].
exist
)
if
(
detections
[
j
].
exist
)
{
{
// compute IOU
// compute IOU
float
intersectionArea
=
(
detections
[
i
].
boundingBox
&
detections
[
j
].
boundingBox
).
area
();
float
intersectionArea
=
float
intersectionRate
=
intersectionArea
/
(
detections
[
i
].
boundingBox
.
area
()
+
detections
[
j
].
boundingBox
.
area
()
-
intersectionArea
);
(
detections
[
i
].
boundingBox
&
detections
[
j
].
boundingBox
).
area
();
float
intersectionRate
=
intersectionArea
/
(
detections
[
i
].
boundingBox
.
area
()
+
detections
[
j
].
boundingBox
.
area
()
-
intersectionArea
);
if
(
intersectionRate
>
IOUThreshold
)
if
(
intersectionRate
>
IOUThreshold
)
{
{
detections
[
j
].
exist
=
false
;
detections
[
j
].
exist
=
false
;
}
}
...
@@ -38,7 +41,6 @@ void NMS(std::vector<ResultOfDetection> &detections, float IOUThreshold)
...
@@ -38,7 +41,6 @@ void NMS(std::vector<ResultOfDetection> &detections, float IOUThreshold)
}
}
}
}
}
}
}
}
}
}
// namespace migraphxSamples
Src/Utility/CommonUtility.h
View file @
906376c1
...
@@ -9,12 +9,12 @@ namespace migraphxSamples
...
@@ -9,12 +9,12 @@ namespace migraphxSamples
{
{
// 排序规则: 按照置信度或者按照面积排序
// 排序规则: 按照置信度或者按照面积排序
bool
CompareConfidence
(
const
ResultOfDetection
&
L
,
const
ResultOfDetection
&
R
);
bool
CompareConfidence
(
const
ResultOfDetection
&
L
,
const
ResultOfDetection
&
R
);
bool
CompareArea
(
const
ResultOfDetection
&
L
,
const
ResultOfDetection
&
R
);
bool
CompareArea
(
const
ResultOfDetection
&
L
,
const
ResultOfDetection
&
R
);
// 非极大抑制
// 非极大抑制
void
NMS
(
std
::
vector
<
ResultOfDetection
>
&
detections
,
float
IOUThreshold
);
void
NMS
(
std
::
vector
<
ResultOfDetection
>&
detections
,
float
IOUThreshold
);
}
}
// namespace migraphxSamples
#endif
#endif
Src/Utility/Filesystem.cpp
View file @
906376c1
This diff is collapsed.
Click to expand it.
Src/Utility/Filesystem.h
View file @
906376c1
...
@@ -5,27 +5,27 @@
...
@@ -5,27 +5,27 @@
#include <string>
#include <string>
#include <vector>
#include <vector>
namespace
migraphxSamples
namespace
migraphxSamples
{
{
// 路径是否存在
// 路径是否存在
bool
Exists
(
const
std
::
string
&
path
);
bool
Exists
(
const
std
::
string
&
path
);
// 路径是否为目录
// 路径是否为目录
bool
IsDirectory
(
const
std
::
string
&
path
);
bool
IsDirectory
(
const
std
::
string
&
path
);
// 是否是路径分隔符(Linux:‘/’,Windows:’\\’)
// 是否是路径分隔符(Linux:‘/’,Windows:’\\’)
bool
IsPathSeparator
(
char
c
);
bool
IsPathSeparator
(
char
c
);
// 路径拼接
// 路径拼接
std
::
string
JoinPath
(
const
std
::
string
&
base
,
const
std
::
string
&
path
);
std
::
string
JoinPath
(
const
std
::
string
&
base
,
const
std
::
string
&
path
);
// 创建多级目录,注意:创建多级目录的时候,目标目录是不能有文件存在的
// 创建多级目录,注意:创建多级目录的时候,目标目录是不能有文件存在的
bool
CreateDirectories
(
const
std
::
string
&
directoryPath
);
bool
CreateDirectories
(
const
std
::
string
&
directoryPath
);
/** 生成符合指定模式的文件名列表(支持递归遍历)
/** 生成符合指定模式的文件名列表(支持递归遍历)
*
*
* pattern: 模式,比如"*.jpg","*.png","*.jpg,*.png"
* pattern: 模式,比如"*.jpg","*.png","*.jpg,*.png"
* addPath:是否包含父路径
* addPath:是否包含父路径
* 注意:
* 注意:
...
@@ -36,35 +36,43 @@ bool CreateDirectories(const std::string &directoryPath);
...
@@ -36,35 +36,43 @@ bool CreateDirectories(const std::string &directoryPath);
5. 不能返回子目录名
5. 不能返回子目录名
*
*
*/
*/
void
GetFileNameList
(
const
std
::
string
&
directory
,
const
std
::
string
&
pattern
,
std
::
vector
<
std
::
string
>
&
result
,
bool
recursive
,
bool
addPath
);
void
GetFileNameList
(
const
std
::
string
&
directory
,
const
std
::
string
&
pattern
,
std
::
vector
<
std
::
string
>&
result
,
bool
recursive
,
bool
addPath
);
// 与GetFileNameList的区别在于如果有子目录,在addPath为true的时候会返回子目录路径(目录名最后有"/")
// 与GetFileNameList的区别在于如果有子目录,在addPath为true的时候会返回子目录路径(目录名最后有"/")
void
GetFileNameList2
(
const
std
::
string
&
directory
,
const
std
::
string
&
pattern
,
std
::
vector
<
std
::
string
>
&
result
,
bool
recursive
,
bool
addPath
);
void
GetFileNameList2
(
const
std
::
string
&
directory
,
const
std
::
string
&
pattern
,
std
::
vector
<
std
::
string
>&
result
,
bool
recursive
,
bool
addPath
);
// 删除文件或者目录,支持递归删除
// 删除文件或者目录,支持递归删除
void
Remove
(
const
std
::
string
&
directory
,
const
std
::
string
&
extension
=
""
);
void
Remove
(
const
std
::
string
&
directory
,
const
std
::
string
&
extension
=
""
);
/** 获取路径的文件名和扩展名
/** 获取路径的文件名和扩展名
*
*
* 示例:path为D:/1/1.txt,则GetFileName()为1.txt,GetFileName_NoExtension()为1,GetExtension()为.txt,GetParentPath()为D:/1/
* 示例:path为D:/1/1.txt,则GetFileName()为1.txt,GetFileName_NoExtension()为1,GetExtension()为.txt,GetParentPath()为D:/1/
*/
*/
std
::
string
GetFileName
(
const
std
::
string
&
path
);
std
::
string
GetFileName
(
const
std
::
string
&
path
);
std
::
string
GetFileName_NoExtension
(
const
std
::
string
&
path
);
std
::
string
GetFileName_NoExtension
(
const
std
::
string
&
path
);
std
::
string
GetExtension
(
const
std
::
string
&
path
);
std
::
string
GetExtension
(
const
std
::
string
&
path
);
std
::
string
GetParentPath
(
const
std
::
string
&
path
);
std
::
string
GetParentPath
(
const
std
::
string
&
path
);
// 拷贝文件
// 拷贝文件
bool
CopyFile
(
const
std
::
string
srcPath
,
const
std
::
string
dstPath
);
bool
CopyFile
(
const
std
::
string
srcPath
,
const
std
::
string
dstPath
);
/** 拷贝目录
/** 拷贝目录
*
*
* 示例:CopyDirectories("D:/0/1/2/","E:/3/");实现把D:/0/1/2/目录拷贝到E:/3/目录中(即拷贝完成后的目录结构为E:/3/2/)
* 示例:CopyDirectories("D:/0/1/2/","E:/3/");实现把D:/0/1/2/目录拷贝到E:/3/目录中(即拷贝完成后的目录结构为E:/3/2/)
* 注意:
* 注意:
1.第一个参数的最后不能加”/”
1.第一个参数的最后不能加”/”
2.不能拷贝隐藏文件
2.不能拷贝隐藏文件
*/
*/
bool
CopyDirectories
(
std
::
string
srcPath
,
const
std
::
string
dstPath
);
bool
CopyDirectories
(
std
::
string
srcPath
,
const
std
::
string
dstPath
);
}
}
// namespace migraphxSamples
#endif
#endif
Src/Utility/SSDDefinition.h
View file @
906376c1
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
namespace
migraphxSamples
namespace
migraphxSamples
{
{
#define SSD_MAX_PRIORBOX_LAYER_NUM
10 // 能够支持的最大检测层数量
#define SSD_MAX_PRIORBOX_LAYER_NUM 10 // 能够支持的最大检测层数量
// SSD参数
// SSD参数
typedef
struct
_SSDParameter
typedef
struct
_SSDParameter
...
@@ -16,23 +16,23 @@ typedef struct _SSDParameter
...
@@ -16,23 +16,23 @@ typedef struct _SSDParameter
int
numberOfPriorBoxLayer
;
// 检测层数量
int
numberOfPriorBoxLayer
;
// 检测层数量
// Model Parameters
// Model Parameters
int
convHeight
[
SSD_MAX_PRIORBOX_LAYER_NUM
*
2
];
int
convHeight
[
SSD_MAX_PRIORBOX_LAYER_NUM
*
2
];
int
convWidth
[
SSD_MAX_PRIORBOX_LAYER_NUM
*
2
];
int
convWidth
[
SSD_MAX_PRIORBOX_LAYER_NUM
*
2
];
int
convChannel
[
SSD_MAX_PRIORBOX_LAYER_NUM
*
2
];
int
convChannel
[
SSD_MAX_PRIORBOX_LAYER_NUM
*
2
];
// PriorBoxLayer Parameters
// PriorBoxLayer Parameters
int
priorBoxWidth
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层priorbox的宽
int
priorBoxWidth
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层priorbox的宽
int
priorBoxHeight
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层priorbox的高
int
priorBoxHeight
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层priorbox的高
std
::
vector
<
std
::
vector
<
float
>>
priorBoxMinSize
;
// 每个检测层priorbox的minsize
std
::
vector
<
std
::
vector
<
float
>>
priorBoxMinSize
;
// 每个检测层priorbox的minsize
std
::
vector
<
std
::
vector
<
float
>>
priorBoxMaxSize
;
// 每个检测层priorbox的maxsize
std
::
vector
<
std
::
vector
<
float
>>
priorBoxMaxSize
;
// 每个检测层priorbox的maxsize
int
minSizeNum
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层priorbox的minsize数量
int
minSizeNum
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层priorbox的minsize数量
int
maxSizeNum
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层priorbox的maxsize数量
int
maxSizeNum
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层priorbox的maxsize数量
int
srcImageHeight
;
// 原图大小
int
srcImageHeight
;
// 原图大小
int
srcImageWidth
;
int
srcImageWidth
;
int
inputAspectRatioNum
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层宽高比的数量
int
inputAspectRatioNum
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层宽高比的数量
std
::
vector
<
std
::
vector
<
float
>>
priorBoxAspectRatio
;
// 每个检测层的宽高比
std
::
vector
<
std
::
vector
<
float
>>
priorBoxAspectRatio
;
// 每个检测层的宽高比
float
priorBoxStepWidth
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层步长的宽
float
priorBoxStepWidth
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层步长的宽
float
priorBoxStepHeight
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层步长的高
float
priorBoxStepHeight
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 每个检测层步长的高
float
offset
;
float
offset
;
int
flip
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
int
flip
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
int
clip
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
int
clip
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
...
@@ -47,7 +47,7 @@ typedef struct _SSDParameter
...
@@ -47,7 +47,7 @@ typedef struct _SSDParameter
int
softMaxOutChn
;
int
softMaxOutChn
;
// DetectionOutLayer Parameters
// DetectionOutLayer Parameters
int
classNum
;
// 类别数(包含背景类)
int
classNum
;
// 类别数(包含背景类)
int
topK
;
int
topK
;
int
keepTopK
;
int
keepTopK
;
int
NMSThresh
;
int
NMSThresh
;
...
@@ -56,39 +56,41 @@ typedef struct _SSDParameter
...
@@ -56,39 +56,41 @@ typedef struct _SSDParameter
int
convStride
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
int
convStride
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// buffer
// buffer
int
*
buffer
;
int
*
buffer
;
int
*
classification
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 分类数据
int
*
classification
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 分类数据
int
*
regression
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 回归
int
*
regression
[
SSD_MAX_PRIORBOX_LAYER_NUM
];
// 回归
int
*
priorboxOutputData
;
int
*
priorboxOutputData
;
int
*
softMaxOutputData
;
int
*
softMaxOutputData
;
int
*
getResultBuffer
;
int
*
getResultBuffer
;
int
*
dstScore
;
int
*
dstScore
;
int
*
dstRoi
;
int
*
dstRoi
;
int
*
classRoiNum
;
int
*
classRoiNum
;
_SSDParameter
()
:
srcImageHeight
(
0
),
_SSDParameter
()
srcImageWidth
(
0
),
:
srcImageHeight
(
0
),
offset
(
0.0
),
srcImageWidth
(
0
),
softMaxInHeight
(
0
),
offset
(
0.0
),
concatNum
(
0
),
softMaxInHeight
(
0
),
softMaxOutWidth
(
0
),
concatNum
(
0
),
softMaxOutHeight
(
0
),
softMaxOutWidth
(
0
),
softMaxOutChn
(
0
),
softMaxOutHeight
(
0
),
buffer
(
NULL
),
softMaxOutChn
(
0
),
priorboxOutputData
(
NULL
),
buffer
(
NULL
),
softMaxOutputData
(
NULL
),
priorboxOutputData
(
NULL
),
getResultBuffer
(
NULL
),
softMaxOutputData
(
NULL
),
dstScore
(
NULL
),
getResultBuffer
(
NULL
),
dstRoi
(
NULL
),
dstScore
(
NULL
),
classRoiNum
(
NULL
){}
dstRoi
(
NULL
),
}
SSDParameter
;
classRoiNum
(
NULL
)
{
}
}
SSDParameter
;
typedef
struct
_QuickSortStack
typedef
struct
_QuickSortStack
{
{
int
min
;
int
min
;
int
max
;
int
max
;
}
QuickSortStack
;
}
QuickSortStack
;
}
}
// namespace migraphxSamples
#endif
#endif
Src/Utility/SimpleLog.h
View file @
906376c1
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
#include <map>
#include <map>
#include <thread>
#include <thread>
#include <mutex>
#include <mutex>
#if
(defined WIN32 || defined _WIN32)
#if(defined WIN32 || defined _WIN32)
#include <Windows.h>
#include <Windows.h>
#else
#else
#include <sys/time.h>
#include <sys/time.h>
...
@@ -16,13 +16,13 @@
...
@@ -16,13 +16,13 @@
using
namespace
std
;
using
namespace
std
;
/** 简易日志
/** 简易日志
*
*
* 不依赖于其他第三方库,只需要包含一个头文件就可以使用。提供了4种日志级别,包括INFO,DEBUG,WARN和ERROR。
* 不依赖于其他第三方库,只需要包含一个头文件就可以使用。提供了4种日志级别,包括INFO,DEBUG,WARN和ERROR。
*
*
* 示例1:
* 示例1:
// 初始化日志,在./Log/目录下创建两个日志文件log1.log和log2.log(注意:目录./Log/需要存在,否则日志创建失败)
//
初始化日志,在./Log/目录下创建两个日志文件log1.log和log2.log(注意:目录./Log/需要存在,否则日志创建失败)
LogManager::GetInstance()->Initialize("./Log/","log1");
LogManager::GetInstance()->Initialize("./Log/","log1");
LogManager::GetInstance()->Initialize("./Log/","log2");
LogManager::GetInstance()->Initialize("./Log/","log2");
...
@@ -34,11 +34,11 @@ using namespace std;
...
@@ -34,11 +34,11 @@ using namespace std;
// 关闭日志
// 关闭日志
LogManager::GetInstance()->Close("log1");
LogManager::GetInstance()->Close("log1");
LogManager::GetInstance()->Close("log2");
LogManager::GetInstance()->Close("log2");
* 示例2:
* 示例2:
// 将日志输出到控制台
// 将日志输出到控制台
string log = "Hello World";
string log = "Hello World";
LOG_INFO(stdout, "%s\n", log.c_str());
LOG_INFO(stdout, "%s\n", log.c_str());
* 注意:
* 注意:
1. 需要C++11
1. 需要C++11
...
@@ -50,44 +50,43 @@ using namespace std;
...
@@ -50,44 +50,43 @@ using namespace std;
class
LogManager
class
LogManager
{
{
private:
private:
LogManager
(){}
LogManager
()
{}
public:
public:
~
LogManager
(){}
~
LogManager
()
{}
inline
void
Initialize
(
const
string
&
parentPath
,
const
string
&
logName
)
inline
void
Initialize
(
const
string
&
parentPath
,
const
string
&
logName
)
{
{
// 日志名为空表示输出到控制台
// 日志名为空表示输出到控制台
if
(
logName
.
size
()
==
0
)
if
(
logName
.
size
()
==
0
)
return
;
return
;
// 查找该日志文件,如果没有则创建
// 查找该日志文件,如果没有则创建
std
::
map
<
string
,
FILE
*>::
const_iterator
iter
=
logMap
.
find
(
logName
);
std
::
map
<
string
,
FILE
*>::
const_iterator
iter
=
logMap
.
find
(
logName
);
if
(
iter
==
logMap
.
end
())
if
(
iter
==
logMap
.
end
())
{
{
string
pathOfLog
=
parentPath
+
logName
+
".log"
;
string
pathOfLog
=
parentPath
+
logName
+
".log"
;
FILE
*
logFile
=
fopen
(
pathOfLog
.
c_str
(),
"a"
);
// w:覆盖原有文件,a:追加
FILE
*
logFile
=
fopen
(
pathOfLog
.
c_str
(),
"a"
);
// w:覆盖原有文件,a:追加
if
(
logFile
!=
NULL
)
if
(
logFile
!=
NULL
)
{
{
logMap
.
insert
(
std
::
make_pair
(
logName
,
logFile
));
logMap
.
insert
(
std
::
make_pair
(
logName
,
logFile
));
}
}
}
}
}
}
inline
FILE
*
GetLogFile
(
const
string
&
logName
)
inline
FILE
*
GetLogFile
(
const
string
&
logName
)
{
{
std
::
map
<
string
,
FILE
*>::
const_iterator
iter
=
logMap
.
find
(
logName
);
std
::
map
<
string
,
FILE
*>::
const_iterator
iter
=
logMap
.
find
(
logName
);
if
(
iter
==
logMap
.
end
())
if
(
iter
==
logMap
.
end
())
{
{
return
NULL
;
return
NULL
;
}
}
return
(
*
iter
).
second
;
return
(
*
iter
).
second
;
}
}
inline
void
Close
(
const
string
&
logName
)
inline
void
Close
(
const
string
&
logName
)
{
{
std
::
map
<
string
,
FILE
*>::
const_iterator
iter
=
logMap
.
find
(
logName
);
std
::
map
<
string
,
FILE
*>::
const_iterator
iter
=
logMap
.
find
(
logName
);
if
(
iter
==
logMap
.
end
())
if
(
iter
==
logMap
.
end
())
{
{
return
;
return
;
}
}
...
@@ -95,10 +94,7 @@ public:
...
@@ -95,10 +94,7 @@ public:
fclose
((
*
iter
).
second
);
fclose
((
*
iter
).
second
);
logMap
.
erase
(
iter
);
logMap
.
erase
(
iter
);
}
}
inline
std
::
mutex
&
GetLogMutex
()
inline
std
::
mutex
&
GetLogMutex
()
{
return
logMutex
;
}
{
return
logMutex
;
}
// Singleton
// Singleton
static
LogManager
*
GetInstance
()
static
LogManager
*
GetInstance
()
...
@@ -106,21 +102,22 @@ public:
...
@@ -106,21 +102,22 @@ public:
static
LogManager
logManager
;
static
LogManager
logManager
;
return
&
logManager
;
return
&
logManager
;
}
}
private:
private:
std
::
map
<
string
,
FILE
*>
logMap
;
std
::
map
<
string
,
FILE
*>
logMap
;
std
::
mutex
logMutex
;
std
::
mutex
logMutex
;
};
};
#ifdef LOG_MUTEX
#ifdef LOG_MUTEX
#define LOCK
LogManager::GetInstance()->GetLogMutex().lock()
#define LOCK
LogManager::GetInstance()->GetLogMutex().lock()
#define UNLOCK
LogManager::GetInstance()->GetLogMutex().unlock()
#define UNLOCK
LogManager::GetInstance()->GetLogMutex().unlock()
#else
#else
#define LOCK
#define LOCK
#define UNLOCK
#define UNLOCK
#endif
#endif
// log time
// log time
typedef
struct
_LogTime
typedef
struct
_LogTime
{
{
string
year
;
string
year
;
string
month
;
string
month
;
...
@@ -131,53 +128,53 @@ typedef struct _LogTime
...
@@ -131,53 +128,53 @@ typedef struct _LogTime
string
millisecond
;
// ms
string
millisecond
;
// ms
string
microsecond
;
// us
string
microsecond
;
// us
string
weekDay
;
string
weekDay
;
}
LogTime
;
}
LogTime
;
inline
LogTime
GetTime
()
inline
LogTime
GetTime
()
{
{
LogTime
currentTime
;
LogTime
currentTime
;
#if
(defined WIN32 || defined _WIN32)
#if(defined WIN32 || defined _WIN32)
SYSTEMTIME
systemTime
;
SYSTEMTIME
systemTime
;
GetLocalTime
(
&
systemTime
);
GetLocalTime
(
&
systemTime
);
char
temp
[
8
]
=
{
0
};
char
temp
[
8
]
=
{
0
};
sprintf
(
temp
,
"%04d"
,
systemTime
.
wYear
);
sprintf
(
temp
,
"%04d"
,
systemTime
.
wYear
);
currentTime
.
year
=
string
(
temp
);
currentTime
.
year
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wMonth
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wMonth
);
currentTime
.
month
=
string
(
temp
);
currentTime
.
month
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wDay
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wDay
);
currentTime
.
day
=
string
(
temp
);
currentTime
.
day
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wHour
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wHour
);
currentTime
.
hour
=
string
(
temp
);
currentTime
.
hour
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wMinute
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wMinute
);
currentTime
.
minute
=
string
(
temp
);
currentTime
.
minute
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wSecond
);
sprintf
(
temp
,
"%02d"
,
systemTime
.
wSecond
);
currentTime
.
second
=
string
(
temp
);
currentTime
.
second
=
string
(
temp
);
sprintf
(
temp
,
"%03d"
,
systemTime
.
wMilliseconds
);
sprintf
(
temp
,
"%03d"
,
systemTime
.
wMilliseconds
);
currentTime
.
millisecond
=
string
(
temp
);
currentTime
.
millisecond
=
string
(
temp
);
sprintf
(
temp
,
"%d"
,
systemTime
.
wDayOfWeek
);
sprintf
(
temp
,
"%d"
,
systemTime
.
wDayOfWeek
);
currentTime
.
weekDay
=
string
(
temp
);
currentTime
.
weekDay
=
string
(
temp
);
#else
#else
struct
timeval
tv
;
struct
timeval
tv
;
struct
tm
*
p
;
struct
tm
*
p
;
gettimeofday
(
&
tv
,
NULL
);
gettimeofday
(
&
tv
,
NULL
);
p
=
localtime
(
&
tv
.
tv_sec
);
p
=
localtime
(
&
tv
.
tv_sec
);
char
temp
[
8
]
=
{
0
};
char
temp
[
8
]
=
{
0
};
sprintf
(
temp
,
"%04d"
,
1900
+
p
->
tm_year
);
sprintf
(
temp
,
"%04d"
,
1900
+
p
->
tm_year
);
currentTime
.
year
=
string
(
temp
);
currentTime
.
year
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
1
+
p
->
tm_mon
);
sprintf
(
temp
,
"%02d"
,
1
+
p
->
tm_mon
);
currentTime
.
month
=
string
(
temp
);
currentTime
.
month
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
p
->
tm_mday
);
sprintf
(
temp
,
"%02d"
,
p
->
tm_mday
);
currentTime
.
day
=
string
(
temp
);
currentTime
.
day
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
p
->
tm_hour
);
sprintf
(
temp
,
"%02d"
,
p
->
tm_hour
);
currentTime
.
hour
=
string
(
temp
);
currentTime
.
hour
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
p
->
tm_min
);
sprintf
(
temp
,
"%02d"
,
p
->
tm_min
);
currentTime
.
minute
=
string
(
temp
);
currentTime
.
minute
=
string
(
temp
);
sprintf
(
temp
,
"%02d"
,
p
->
tm_sec
);
sprintf
(
temp
,
"%02d"
,
p
->
tm_sec
);
currentTime
.
second
=
string
(
temp
);
currentTime
.
second
=
string
(
temp
);
sprintf
(
temp
,
"%03d"
,(
int
)(
tv
.
tv_usec
/
1000
));
sprintf
(
temp
,
"%03d"
,
(
int
)(
tv
.
tv_usec
/
1000
));
currentTime
.
millisecond
=
string
(
temp
);
currentTime
.
millisecond
=
string
(
temp
);
sprintf
(
temp
,
"%03d"
,
(
int
)(
tv
.
tv_usec
%
1000
));
sprintf
(
temp
,
"%03d"
,
(
int
)(
tv
.
tv_usec
%
1000
));
currentTime
.
microsecond
=
string
(
temp
);
currentTime
.
microsecond
=
string
(
temp
);
...
@@ -187,61 +184,83 @@ inline LogTime GetTime()
...
@@ -187,61 +184,83 @@ inline LogTime GetTime()
return
currentTime
;
return
currentTime
;
}
}
#define LOG_TIME(logFile) \
#define LOG_TIME(logFile) \
do\
do \
{\
{ \
LogTime currentTime=GetTime(); \
LogTime currentTime = GetTime(); \
fprintf(((logFile == NULL) ? stdout : logFile), "%s-%s-%s %s:%s:%s.%s\t",currentTime.year.c_str(),currentTime.month.c_str(),currentTime.day.c_str(),currentTime.hour.c_str(),currentTime.minute.c_str(),currentTime.second.c_str(),currentTime.millisecond.c_str()); \
fprintf(((logFile == NULL) ? stdout : logFile), \
}while (0)
"%s-%s-%s %s:%s:%s.%s\t", \
currentTime.year.c_str(), \
currentTime.month.c_str(), \
#define LOG_INFO(logFile,logInfo, ...) \
currentTime.day.c_str(), \
do\
currentTime.hour.c_str(), \
{\
currentTime.minute.c_str(), \
LOCK; \
currentTime.second.c_str(), \
LOG_TIME(logFile); \
currentTime.millisecond.c_str()); \
fprintf(((logFile == NULL) ? stdout : logFile), "INFO\t"); \
} while(0)
fprintf(((logFile == NULL) ? stdout : logFile), "[%s:%d (%s) ]: ", __FILE__, __LINE__, __FUNCTION__); \
fprintf(((logFile == NULL) ? stdout : logFile), logInfo, ## __VA_ARGS__); \
fflush(logFile); \
UNLOCK; \
} while (0)
#define LOG_DEBUG(logFile,logInfo, ...) \
do\
{\
LOCK; \
LOG_TIME(logFile);\
fprintf(((logFile==NULL)?stdout:logFile), "DEBUG\t"); \
fprintf(((logFile==NULL)?stdout:logFile), "[%s:%d (%s) ]: ", __FILE__, __LINE__, __FUNCTION__); \
fprintf(((logFile==NULL)?stdout:logFile),logInfo, ## __VA_ARGS__); \
fflush(logFile); \
UNLOCK; \
} while (0)
#define LOG_ERROR(logFile,logInfo, ...) \
do\
{\
LOCK; \
LOG_TIME(logFile);\
fprintf(((logFile==NULL)?stdout:logFile), "ERROR\t"); \
fprintf(((logFile==NULL)?stdout:logFile), "[%s:%d (%s) ]: ", __FILE__, __LINE__, __FUNCTION__); \
fprintf(((logFile==NULL)?stdout:logFile),logInfo, ## __VA_ARGS__); \
fflush(logFile); \
UNLOCK; \
} while (0)
#define LOG_WARN(logFile,logInfo, ...) \
do\
{\
LOCK; \
LOG_TIME(logFile);\
fprintf(((logFile==NULL)?stdout:logFile), "WARN\t"); \
fprintf(((logFile==NULL)?stdout:logFile), "[%s:%d (%s) ]: ", __FILE__, __LINE__, __FUNCTION__); \
fprintf(((logFile==NULL)?stdout:logFile),logInfo, ## __VA_ARGS__); \
fflush(logFile); \
UNLOCK; \
} while (0)
#endif // __SIMPLE_LOG_H__
#define LOG_INFO(logFile, logInfo, ...) \
do \
{ \
LOCK; \
LOG_TIME(logFile); \
fprintf(((logFile == NULL) ? stdout : logFile), "INFO\t"); \
fprintf(((logFile == NULL) ? stdout : logFile), \
"[%s:%d (%s) ]: ", \
__FILE__, \
__LINE__, \
__FUNCTION__); \
fprintf(((logFile == NULL) ? stdout : logFile), logInfo, ##__VA_ARGS__); \
fflush(logFile); \
UNLOCK; \
} while(0)
#define LOG_DEBUG(logFile, logInfo, ...) \
do \
{ \
LOCK; \
LOG_TIME(logFile); \
fprintf(((logFile == NULL) ? stdout : logFile), "DEBUG\t"); \
fprintf(((logFile == NULL) ? stdout : logFile), \
"[%s:%d (%s) ]: ", \
__FILE__, \
__LINE__, \
__FUNCTION__); \
fprintf(((logFile == NULL) ? stdout : logFile), logInfo, ##__VA_ARGS__); \
fflush(logFile); \
UNLOCK; \
} while(0)
#define LOG_ERROR(logFile, logInfo, ...) \
do \
{ \
LOCK; \
LOG_TIME(logFile); \
fprintf(((logFile == NULL) ? stdout : logFile), "ERROR\t"); \
fprintf(((logFile == NULL) ? stdout : logFile), \
"[%s:%d (%s) ]: ", \
__FILE__, \
__LINE__, \
__FUNCTION__); \
fprintf(((logFile == NULL) ? stdout : logFile), logInfo, ##__VA_ARGS__); \
fflush(logFile); \
UNLOCK; \
} while(0)
#define LOG_WARN(logFile, logInfo, ...) \
do \
{ \
LOCK; \
LOG_TIME(logFile); \
fprintf(((logFile == NULL) ? stdout : logFile), "WARN\t"); \
fprintf(((logFile == NULL) ? stdout : logFile), \
"[%s:%d (%s) ]: ", \
__FILE__, \
__LINE__, \
__FUNCTION__); \
fprintf(((logFile == NULL) ? stdout : logFile), logInfo, ##__VA_ARGS__); \
fflush(logFile); \
UNLOCK; \
} while(0)
#endif // __SIMPLE_LOG_H__
Src/main.cpp
View file @
906376c1
...
@@ -11,8 +11,8 @@ int main()
...
@@ -11,8 +11,8 @@ int main()
migraphxSamples
::
DetectorRetinaFace
detector
;
migraphxSamples
::
DetectorRetinaFace
detector
;
migraphxSamples
::
InitializationParameterOfDetector
initParamOfDetectorRetinaFace
;
migraphxSamples
::
InitializationParameterOfDetector
initParamOfDetectorRetinaFace
;
initParamOfDetectorRetinaFace
.
configFilePath
=
CONFIG_FILE
;
initParamOfDetectorRetinaFace
.
configFilePath
=
CONFIG_FILE
;
migraphxSamples
::
ErrorCode
errorCode
=
detector
.
Initialize
(
initParamOfDetectorRetinaFace
);
migraphxSamples
::
ErrorCode
errorCode
=
detector
.
Initialize
(
initParamOfDetectorRetinaFace
);
if
(
errorCode
!=
migraphxSamples
::
SUCCESS
)
if
(
errorCode
!=
migraphxSamples
::
SUCCESS
)
{
{
LOG_ERROR
(
stdout
,
"fail to initialize detector!
\n
"
);
LOG_ERROR
(
stdout
,
"fail to initialize detector!
\n
"
);
exit
(
-
1
);
exit
(
-
1
);
...
@@ -20,24 +20,30 @@ int main()
...
@@ -20,24 +20,30 @@ int main()
LOG_INFO
(
stdout
,
"succeed to initialize detector
\n
"
);
LOG_INFO
(
stdout
,
"succeed to initialize detector
\n
"
);
// 读取测试图片
// 读取测试图片
cv
::
Mat
srcImage
=
cv
::
imread
(
"../Resource/Images/FaceDetect.jpg"
,
1
);
cv
::
Mat
srcImage
=
cv
::
imread
(
"../Resource/Images/FaceDetect.jpg"
,
1
);
// 推理
// 推理
std
::
vector
<
migraphxSamples
::
ResultOfDetection
>
predictions
;
std
::
vector
<
migraphxSamples
::
ResultOfDetection
>
predictions
;
detector
.
Detect
(
srcImage
,
predictions
);
detector
.
Detect
(
srcImage
,
predictions
);
// 获取推理结果
// 获取推理结果
LOG_INFO
(
stdout
,
"========== Detection Results ==========
\n
"
);
LOG_INFO
(
stdout
,
"========== Detection Results ==========
\n
"
);
for
(
int
i
=
0
;
i
<
predictions
.
size
();
++
i
)
for
(
int
i
=
0
;
i
<
predictions
.
size
();
++
i
)
{
{
migraphxSamples
::
ResultOfDetection
result
=
predictions
[
i
];
migraphxSamples
::
ResultOfDetection
result
=
predictions
[
i
];
cv
::
rectangle
(
srcImage
,
result
.
boundingBox
,
cv
::
Scalar
(
0
,
255
,
255
),
2
);
cv
::
rectangle
(
srcImage
,
result
.
boundingBox
,
cv
::
Scalar
(
0
,
255
,
255
),
2
);
LOG_INFO
(
stdout
,
"box:%d %d %d %d,label:%d,confidence:%f
\n
"
,
predictions
[
i
].
boundingBox
.
x
,
LOG_INFO
(
stdout
,
predictions
[
i
].
boundingBox
.
y
,
predictions
[
i
].
boundingBox
.
width
,
predictions
[
i
].
boundingBox
.
height
,
predictions
[
i
].
classID
,
predictions
[
i
].
confidence
);
"box:%d %d %d %d,label:%d,confidence:%f
\n
"
,
predictions
[
i
].
boundingBox
.
x
,
predictions
[
i
].
boundingBox
.
y
,
predictions
[
i
].
boundingBox
.
width
,
predictions
[
i
].
boundingBox
.
height
,
predictions
[
i
].
classID
,
predictions
[
i
].
confidence
);
}
}
cv
::
imwrite
(
"Result.jpg"
,
srcImage
);
cv
::
imwrite
(
"Result.jpg"
,
srcImage
);
LOG_INFO
(
stdout
,
"Detection results have been saved to ./Result.jpg
\n
"
);
LOG_INFO
(
stdout
,
"Detection results have been saved to ./Result.jpg
\n
"
);
return
0
;
return
0
;
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment