Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sq975
openpose
提交
a2032494
O
openpose
项目概览
sq975
/
openpose
与 Fork 源项目一致
从无法访问的项目Fork
通知
7
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
O
openpose
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
a2032494
编写于
3月 30, 2018
作者:
G
gineshidalgo99
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Flir camera: sw trigger + dedicated read thread
上级
200c29cc
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
247 addition
and
117 deletion
+247
-117
doc/release_notes.md
doc/release_notes.md
+1
-0
src/openpose/producer/spinnakerWrapper.cpp
src/openpose/producer/spinnakerWrapper.cpp
+167
-45
src/openpose/producer/webcamReader.cpp
src/openpose/producer/webcamReader.cpp
+15
-8
src/openpose/utilities/fileSystem.cpp
src/openpose/utilities/fileSystem.cpp
+64
-64
未找到文件。
doc/release_notes.md
浏览文件 @
a2032494
...
...
@@ -213,6 +213,7 @@ OpenPose Library - Release Notes
## Current version - future OpenPose 1.3.1
1.
Main improvements:
1.
Flir cameras: Added software trigger and a dedicated thread to keep reading images to remove latency (analogously to webcamReader).
2.
Functions or parameters renamed:
3.
Main bugs fixed:
...
...
src/openpose/producer/spinnakerWrapper.cpp
浏览文件 @
a2032494
...
...
@@ -166,7 +166,8 @@ namespace op
{
int
result
=
0
;
log
(
"*** CONFIGURING TRIGGER ***"
,
Priority
::
High
);
log
(
"Configuring hardware trigger..."
,
Priority
::
High
);
log
(
"Configuring trigger..."
,
Priority
::
High
);
// log("Configuring hardware trigger...", Priority::High);
// Ensure trigger mode off
// *** NOTES ***
// The trigger must be disabled in order to configure whether the source
...
...
@@ -196,16 +197,23 @@ namespace op
error
(
"Unable to set trigger mode (node retrieval). Aborting..."
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
// Set trigger mode to hardware ('Line0')
Spinnaker
::
GenApi
::
CEnumEntryPtr
ptrTriggerSourceHardware
=
ptrTriggerSource
->
GetEntryByName
(
"Line0"
);
if
(
!
Spinnaker
::
GenApi
::
IsAvailable
(
ptrTriggerSourceHardware
)
||
!
Spinnaker
::
GenApi
::
IsReadable
(
ptrTriggerSourceHardware
))
// // Set trigger mode to hardware ('Line0')
// Spinnaker::GenApi::CEnumEntryPtr ptrTriggerSourceHardware = ptrTriggerSource->GetEntryByName("Line0");
// if (!Spinnaker::GenApi::IsAvailable(ptrTriggerSourceHardware)
// || !Spinnaker::GenApi::IsReadable(ptrTriggerSourceHardware))
// error("Unable to set trigger mode (enum entry retrieval). Aborting...",
// __LINE__, __FUNCTION__, __FILE__);
// ptrTriggerSource->SetIntValue(ptrTriggerSourceHardware->GetValue());
// log("Trigger source set to hardware...", Priority::High);
// Set trigger mode to sofware
Spinnaker
::
GenApi
::
CEnumEntryPtr
ptrTriggerSourceSoftware
=
ptrTriggerSource
->
GetEntryByName
(
"Software"
);
if
(
!
Spinnaker
::
GenApi
::
IsAvailable
(
ptrTriggerSourceSoftware
)
||
!
Spinnaker
::
GenApi
::
IsReadable
(
ptrTriggerSourceSoftware
))
error
(
"Unable to set trigger mode (enum entry retrieval). Aborting..."
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
ptrTriggerSource
->
SetIntValue
(
ptrTriggerSourceHardware
->
GetValue
());
log
(
"Trigger source set to hardware..."
,
Priority
::
High
);
ptrTriggerSource
->
SetIntValue
(
ptrTriggerSourceSoftware
->
GetValue
());
// log("Trigger source set to source...", Priority::High);
// Turn trigger mode on
// *** LATER ***
...
...
@@ -237,6 +245,34 @@ namespace op
return
-
1
;
}
}
int
GrabNextImageByTrigger
(
Spinnaker
::
GenApi
::
INodeMap
&
nodeMap
)
{
try
{
int
result
=
0
;
// Execute software trigger
Spinnaker
::
GenApi
::
CCommandPtr
ptrSoftwareTriggerCommand
=
nodeMap
.
GetNode
(
"TriggerSoftware"
);
if
(
!
IsAvailable
(
ptrSoftwareTriggerCommand
)
||
!
IsWritable
(
ptrSoftwareTriggerCommand
))
error
(
"Unable to enable trigger. Aborting..."
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
ptrSoftwareTriggerCommand
->
Execute
();
return
result
;
}
catch
(
const
Spinnaker
::
Exception
&
e
)
{
error
(
e
.
what
(),
__LINE__
,
__FUNCTION__
,
__FILE__
);
return
-
1
;
}
catch
(
const
std
::
exception
&
e
)
{
error
(
e
.
what
(),
__LINE__
,
__FUNCTION__
,
__FILE__
);
return
-
1
;
}
}
#else
const
std
::
string
WITH_FLIR_CAMERA_ERROR
{
"OpenPose CMake must be compiled with the `WITH_FLIR_CAMERA`"
" flag in order to use the FLIR camera. Alternatively, disable `--flir_camera`."
};
...
...
@@ -251,6 +287,12 @@ namespace op
Spinnaker
::
CameraList
mCameraList
;
Spinnaker
::
SystemPtr
mSystemPtr
;
std
::
vector
<
cv
::
Mat
>
mCvMats
;
// Thread
bool
mThreadOpened
;
std
::
vector
<
Spinnaker
::
ImagePtr
>
mBuffer
;
std
::
mutex
mBufferMutex
;
std
::
atomic
<
bool
>
mCloseThread
;
std
::
thread
mThread
;
ImplSpinnakerWrapper
()
:
mInitialized
{
false
}
...
...
@@ -272,9 +314,60 @@ namespace op
cv
::
undistort
(
cvMatDistorted
,
mCvMats
[
i
],
cameraIntrinsics
,
cameraDistorsions
);
}
void
bufferingThread
()
{
#ifdef WITH_FLIR_CAMERA
try
{
mCloseThread
=
false
;
// Get cameras - ~0.005 ms (3 cameras)
std
::
vector
<
Spinnaker
::
CameraPtr
>
cameraPtrs
(
mCameraList
.
GetSize
());
for
(
auto
i
=
0u
;
i
<
cameraPtrs
.
size
();
i
++
)
cameraPtrs
.
at
(
i
)
=
mCameraList
.
GetByIndex
(
i
);
while
(
!
mCloseThread
)
{
// Trigger
for
(
auto
i
=
0u
;
i
<
cameraPtrs
.
size
();
i
++
)
{
// Retrieve GenICam nodemap
auto
&
iNodeMap
=
cameraPtrs
[
i
]
->
GetNodeMap
();
Spinnaker
::
GenApi
::
CEnumerationPtr
ptrAcquisitionMode
=
iNodeMap
.
GetNode
(
"AcquisitionMode"
);
const
auto
result
=
GrabNextImageByTrigger
(
iNodeMap
);
if
(
result
!=
0
)
error
(
"Error in GrabNextImageByTrigger."
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
}
// Get frame
std
::
vector
<
Spinnaker
::
ImagePtr
>
imagePtrs
(
cameraPtrs
.
size
());
for
(
auto
i
=
0u
;
i
<
cameraPtrs
.
size
();
i
++
)
imagePtrs
.
at
(
i
)
=
cameraPtrs
.
at
(
i
)
->
GetNextImage
();
// Move to buffer
bool
imagesExtracted
=
true
;
for
(
auto
&
imagePtr
:
imagePtrs
)
{
if
(
imagePtr
->
IsIncomplete
())
{
log
(
"Image incomplete with image status "
+
std
::
to_string
(
imagePtr
->
GetImageStatus
())
+
"..."
,
Priority
::
High
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
imagesExtracted
=
false
;
break
;
}
}
if
(
imagesExtracted
)
{
const
std
::
lock_guard
<
std
::
mutex
>
lock
{
mBufferMutex
};
std
::
swap
(
mBuffer
,
imagePtrs
);
}
}
}
catch
(
const
std
::
exception
&
e
)
{
error
(
e
.
what
(),
__LINE__
,
__FUNCTION__
,
__FILE__
);
}
#endif
}
// This function acquires and displays images from each device.
std
::
vector
<
cv
::
Mat
>
acquireImages
(
Spinnaker
::
CameraList
&
cameraList
,
const
std
::
vector
<
cv
::
Mat
>&
cameraIntrinsics
,
std
::
vector
<
cv
::
Mat
>
acquireImages
(
const
std
::
vector
<
cv
::
Mat
>&
cameraIntrinsics
,
const
std
::
vector
<
cv
::
Mat
>&
cameraDistorsions
)
{
try
...
...
@@ -287,15 +380,34 @@ namespace op
// through the cameras; otherwise, all images will be grabbed from a
// single camera before grabbing any images from another.
// Get cameras - ~0.005 ms (3 cameras)
std
::
vector
<
Spinnaker
::
CameraPtr
>
cameraPtrs
(
cameraList
.
GetSize
());
for
(
auto
i
=
0u
;
i
<
cameraPtrs
.
size
();
i
++
)
cameraPtrs
.
at
(
i
)
=
cameraList
.
GetByIndex
(
i
);
//
//
Get cameras - ~0.005 ms (3 cameras)
//
std::vector<Spinnaker::CameraPtr> cameraPtrs(cameraList.GetSize());
//
for (auto i = 0u; i < cameraPtrs.size(); i++)
//
cameraPtrs.at(i) = cameraList.GetByIndex(i);
// Read raw images - ~0.15 ms (3 cameras)
std
::
vector
<
Spinnaker
::
ImagePtr
>
imagePtrs
(
cameraPtrs
.
size
());
for
(
auto
i
=
0u
;
i
<
cameraPtrs
.
size
();
i
++
)
imagePtrs
.
at
(
i
)
=
cameraPtrs
.
at
(
i
)
->
GetNextImage
();
// std::vector<Spinnaker::ImagePtr> imagePtrs(cameraPtrs.size());
// for (auto i = 0u; i < cameraPtrs.size(); i++)
// imagePtrs.at(i) = cameraPtrs.at(i)->GetNextImage();
std
::
vector
<
Spinnaker
::
ImagePtr
>
imagePtrs
;
// Retrieve frame
auto
cvMatRetrieved
=
false
;
while
(
!
cvMatRetrieved
)
{
// Retrieve frame
std
::
unique_lock
<
std
::
mutex
>
lock
{
mBufferMutex
};
if
(
!
mBuffer
.
empty
())
{
std
::
swap
(
imagePtrs
,
mBuffer
);
cvMatRetrieved
=
true
;
}
// No frames available -> sleep & wait
else
{
lock
.
unlock
();
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
microseconds
{
5
});
}
}
// Commented code was supposed to clean buffer, but `NewestFirstOverwrite` does that
// Getting frames
// Retrieve next received image and ensure image completion
...
...
@@ -452,37 +564,37 @@ namespace op
// acquired.
cameraPtr
->
Init
();
//
//
Retrieve GenICam nodemap
//
auto& iNodeMap = cameraPtr->GetNodeMap();
// Retrieve GenICam nodemap
auto
&
iNodeMap
=
cameraPtr
->
GetNodeMap
();
//
//
Configure trigger
//
int result = configureTrigger(iNodeMap);
//
if (result < 0)
//
error("Result > 0, error " + std::to_string(result) + " occurred...",
//
__LINE__, __FUNCTION__, __FILE__);
// Configure trigger
int
result
=
configureTrigger
(
iNodeMap
);
if
(
result
<
0
)
error
(
"Result > 0, error "
+
std
::
to_string
(
result
)
+
" occurred..."
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
// // Configure chunk data
// result = configureChunkData(iNodeMap);
// if (result < 0)
// return result;
// Remove buffer --> Always get newest frame
Spinnaker
::
GenApi
::
INodeMap
&
snodeMap
=
cameraPtr
->
GetTLStreamNodeMap
();
Spinnaker
::
GenApi
::
CEnumerationPtr
ptrBufferHandlingMode
=
snodeMap
.
GetNode
(
"StreamBufferHandlingMode"
);
if
(
!
Spinnaker
::
GenApi
::
IsAvailable
(
ptrBufferHandlingMode
)
||
!
Spinnaker
::
GenApi
::
IsWritable
(
ptrBufferHandlingMode
))
error
(
"Unable to change buffer handling mode"
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
Spinnaker
::
GenApi
::
CEnumEntryPtr
ptrBufferHandlingModeNewest
=
ptrBufferHandlingMode
->
GetEntryByName
(
"NewestFirstOverwrite"
);
if
(
!
Spinnaker
::
GenApi
::
IsAvailable
(
ptrBufferHandlingModeNewest
)
||
!
IsReadable
(
ptrBufferHandlingModeNewest
))
error
(
"Unable to set buffer handling mode to newest (entry 'NewestFirstOverwrite' retrieval)."
" Aborting..."
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
int64_t
bufferHandlingModeNewest
=
ptrBufferHandlingModeNewest
->
GetValue
();
ptrBufferHandlingMode
->
SetIntValue
(
bufferHandlingModeNewest
);
//
//
Remove buffer --> Always get newest frame
//
Spinnaker::GenApi::INodeMap& snodeMap = cameraPtr->GetTLStreamNodeMap();
//
Spinnaker::GenApi::CEnumerationPtr ptrBufferHandlingMode = snodeMap.GetNode(
//
"StreamBufferHandlingMode");
//
if (!Spinnaker::GenApi::IsAvailable(ptrBufferHandlingMode)
//
|| !Spinnaker::GenApi::IsWritable(ptrBufferHandlingMode))
//
error("Unable to change buffer handling mode", __LINE__, __FUNCTION__, __FILE__);
//
Spinnaker::GenApi::CEnumEntryPtr ptrBufferHandlingModeNewest = ptrBufferHandlingMode->GetEntryByName(
//
"NewestFirstOverwrite");
//
if (!Spinnaker::GenApi::IsAvailable(ptrBufferHandlingModeNewest)
//
|| !IsReadable(ptrBufferHandlingModeNewest))
//
error("Unable to set buffer handling mode to newest (entry 'NewestFirstOverwrite' retrieval)."
//
" Aborting...", __LINE__, __FUNCTION__, __FILE__);
//
int64_t bufferHandlingModeNewest = ptrBufferHandlingModeNewest->GetValue();
//
ptrBufferHandlingMode->SetIntValue(bufferHandlingModeNewest);
}
// Prepare each camera to acquire images
...
...
@@ -589,6 +701,10 @@ namespace op
serialNumbers
[
i
]
=
strSerialNumbers
[
i
];
upImpl
->
mCameraParameterReader
.
readParameters
(
cameraParameterPath
,
serialNumbers
);
// Start buffering thread
upImpl
->
mThreadOpened
=
true
;
upImpl
->
mThread
=
std
::
thread
{
&
SpinnakerWrapper
::
ImplSpinnakerWrapper
::
bufferingThread
,
this
->
upImpl
};
// Get resolution + security checks
const
auto
cvMats
=
getRawFrames
();
// Security checks
...
...
@@ -599,7 +715,6 @@ namespace op
upImpl
->
mResolution
=
Point
<
int
>
{
cvMats
[
0
].
cols
,
cvMats
[
0
].
rows
};
log
(
"
\n
Running for all cameras...
\n\n
*** IMAGE ACQUISITION ***
\n
"
,
Priority
::
High
);
}
catch
(
const
Spinnaker
::
Exception
&
e
)
{
...
...
@@ -640,8 +755,7 @@ namespace op
!=
upImpl
->
mCameraParameterReader
.
getNumberCameras
())
error
(
"The number of cameras must be the same as the INTRINSICS vector size."
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
return
upImpl
->
acquireImages
(
upImpl
->
mCameraList
,
upImpl
->
mCameraParameterReader
.
getCameraIntrinsics
(),
return
upImpl
->
acquireImages
(
upImpl
->
mCameraParameterReader
.
getCameraIntrinsics
(),
upImpl
->
mCameraParameterReader
.
getCameraDistortions
());
}
catch
(
const
Spinnaker
::
Exception
&
e
)
...
...
@@ -719,6 +833,14 @@ namespace op
{
if
(
upImpl
->
mInitialized
)
{
// Stop thread
// Close and join thread
if
(
upImpl
->
mThreadOpened
)
{
upImpl
->
mCloseThread
=
true
;
upImpl
->
mThread
.
join
();
}
// End acquisition for each camera
// Notice that what is usually a one-step process is now two steps
// because of the additional step of selecting the camera. It is worth
...
...
src/openpose/producer/webcamReader.cpp
浏览文件 @
a2032494
...
...
@@ -170,17 +170,24 @@ namespace op
void
WebcamReader
::
bufferingThread
()
{
mCloseThread
=
false
;
while
(
!
mCloseThread
)
try
{
// Get frame
auto
cvMat
=
VideoCaptureReader
::
getRawFrame
();
// Move to buffer
if
(
!
cvMat
.
empty
())
mCloseThread
=
false
;
while
(
!
mCloseThread
)
{
const
std
::
lock_guard
<
std
::
mutex
>
lock
{
mBufferMutex
};
std
::
swap
(
mBuffer
,
cvMat
);
// Get frame
auto
cvMat
=
VideoCaptureReader
::
getRawFrame
();
// Move to buffer
if
(
!
cvMat
.
empty
())
{
const
std
::
lock_guard
<
std
::
mutex
>
lock
{
mBufferMutex
};
std
::
swap
(
mBuffer
,
cvMat
);
}
}
}
catch
(
const
std
::
exception
&
e
)
{
error
(
e
.
what
(),
__LINE__
,
__FUNCTION__
,
__FILE__
);
}
}
}
src/openpose/utilities/fileSystem.cpp
浏览文件 @
a2032494
...
...
@@ -19,9 +19,9 @@ namespace op
{
if
(
!
directoryPath
.
empty
())
{
// Format the path first
const
auto
formatedPath
=
formatAsDirectory
(
directoryPath
);
// Create dir if it doesn't exist yet
// Format the path first
const
auto
formatedPath
=
formatAsDirectory
(
directoryPath
);
// Create dir if it doesn't exist yet
if
(
!
existDirectory
(
formatedPath
))
{
#ifdef _WIN32
...
...
@@ -50,31 +50,31 @@ namespace op
{
try
{
// Format the path first
const
auto
formatedPath
=
formatAsDirectory
(
directoryPath
);
#ifdef _WIN32
DWORD
status
=
GetFileAttributesA
(
formatedPath
.
c_str
());
// It is not a directory
if
(
status
==
INVALID_FILE_ATTRIBUTES
)
return
false
;
// It is a directory
else
if
(
status
&
FILE_ATTRIBUTE_DIRECTORY
)
return
true
;
// It is not a directory
return
false
;
// this is not a directory!
#elif defined __unix__
// It is a directory
if
(
auto
*
directory
=
opendir
(
formatedPath
.
c_str
()))
{
closedir
(
directory
);
return
true
;
}
// It is not a directory
else
return
false
;
#else
#error Unknown environment!
#endif
// Format the path first
const
auto
formatedPath
=
formatAsDirectory
(
directoryPath
);
#ifdef _WIN32
DWORD
status
=
GetFileAttributesA
(
formatedPath
.
c_str
());
// It is not a directory
if
(
status
==
INVALID_FILE_ATTRIBUTES
)
return
false
;
// It is a directory
else
if
(
status
&
FILE_ATTRIBUTE_DIRECTORY
)
return
true
;
// It is not a directory
return
false
;
// this is not a directory!
#elif defined __unix__
// It is a directory
if
(
auto
*
directory
=
opendir
(
formatedPath
.
c_str
()))
{
closedir
(
directory
);
return
true
;
}
// It is not a directory
else
return
false
;
#else
#error Unknown environment!
#endif
}
catch
(
const
std
::
exception
&
e
)
{
...
...
@@ -109,14 +109,14 @@ namespace op
std
::
string
directoryPath
=
directoryPathString
;
if
(
!
directoryPath
.
empty
())
{
// Replace all '\\' to '/'
std
::
replace
(
directoryPath
.
begin
(),
directoryPath
.
end
(),
'\\'
,
'/'
);
if
(
directoryPath
.
back
()
!=
'/'
)
// Replace all '\\' to '/'
std
::
replace
(
directoryPath
.
begin
(),
directoryPath
.
end
(),
'\\'
,
'/'
);
if
(
directoryPath
.
back
()
!=
'/'
)
directoryPath
=
directoryPath
+
"/"
;
// Windows - Replace all '/' to '\\'
#ifdef _WIN32
std
::
replace
(
directoryPath
.
begin
(),
directoryPath
.
end
(),
'/'
,
'\\'
);
#endif
// Windows - Replace all '/' to '\\'
#ifdef _WIN32
std
::
replace
(
directoryPath
.
begin
(),
directoryPath
.
end
(),
'/'
,
'\\'
);
#endif
}
return
directoryPath
;
}
...
...
@@ -235,35 +235,35 @@ namespace op
if
(
!
existDirectory
(
formatedPath
))
error
(
"Folder "
+
formatedPath
+
" does not exist."
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
// Read all files in folder
std
::
vector
<
std
::
string
>
filePaths
;
#ifdef _WIN32
auto
formatedPathWindows
=
formatedPath
;
formatedPathWindows
.
append
(
"
\\
*"
);
WIN32_FIND_DATA
data
;
HANDLE
hFind
;
if
((
hFind
=
FindFirstFile
(
formatedPathWindows
.
c_str
(),
&
data
))
!=
INVALID_HANDLE_VALUE
)
{
do
filePaths
.
emplace_back
(
formatedPath
+
data
.
cFileName
);
while
(
FindNextFile
(
hFind
,
&
data
)
!=
0
);
FindClose
(
hFind
);
}
#elif defined __unix__
std
::
shared_ptr
<
DIR
>
directoryPtr
(
opendir
(
formatedPath
.
c_str
()),
[](
DIR
*
formatedPath
){
formatedPath
&&
closedir
(
formatedPath
);
}
);
struct
dirent
*
direntPtr
;
while
((
direntPtr
=
readdir
(
directoryPtr
.
get
()))
!=
nullptr
)
{
std
::
string
currentPath
=
formatedPath
+
direntPtr
->
d_name
;
if
((
strncmp
(
direntPtr
->
d_name
,
"."
,
1
)
==
0
)
||
existDirectory
(
currentPath
))
continue
;
filePaths
.
emplace_back
(
currentPath
);
}
#else
#error Unknown environment!
#endif
std
::
vector
<
std
::
string
>
filePaths
;
#ifdef _WIN32
auto
formatedPathWindows
=
formatedPath
;
formatedPathWindows
.
append
(
"
\\
*"
);
WIN32_FIND_DATA
data
;
HANDLE
hFind
;
if
((
hFind
=
FindFirstFile
(
formatedPathWindows
.
c_str
(),
&
data
))
!=
INVALID_HANDLE_VALUE
)
{
do
filePaths
.
emplace_back
(
formatedPath
+
data
.
cFileName
);
while
(
FindNextFile
(
hFind
,
&
data
)
!=
0
);
FindClose
(
hFind
);
}
#elif defined __unix__
std
::
shared_ptr
<
DIR
>
directoryPtr
(
opendir
(
formatedPath
.
c_str
()),
[](
DIR
*
formatedPath
){
formatedPath
&&
closedir
(
formatedPath
);
}
);
struct
dirent
*
direntPtr
;
while
((
direntPtr
=
readdir
(
directoryPtr
.
get
()))
!=
nullptr
)
{
std
::
string
currentPath
=
formatedPath
+
direntPtr
->
d_name
;
if
((
strncmp
(
direntPtr
->
d_name
,
"."
,
1
)
==
0
)
||
existDirectory
(
currentPath
))
continue
;
filePaths
.
emplace_back
(
currentPath
);
}
#else
#error Unknown environment!
#endif
// Check #files > 0
if
(
filePaths
.
empty
())
error
(
"No files were found on "
+
formatedPath
,
__LINE__
,
__FUNCTION__
,
__FILE__
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录