Add raw sources and sinks to cscore (#1670)

In some cases, we don't want the cv requirement to get an image, for instance interop with other versions of opencv

This enables getting a raw image, and handling conversions from the user side.
This commit is contained in:
Thad House
2019-05-30 19:12:05 -07:00
committed by Peter Johnson
parent 7de9477347
commit fb1239a2ad
37 changed files with 2218 additions and 504 deletions

View File

@@ -20,8 +20,6 @@
extern "C" {
#endif
struct CvMat;
/**
* @defgroup cscore_c_api cscore C API
*
@@ -128,7 +126,8 @@ enum CS_SourceKind {
CS_SOURCE_UNKNOWN = 0,
CS_SOURCE_USB = 1,
CS_SOURCE_HTTP = 2,
CS_SOURCE_CV = 4
CS_SOURCE_CV = 4,
CS_SOURCE_RAW = 8,
};
/**
@@ -144,7 +143,12 @@ enum CS_HttpCameraKind {
/**
* Sink kinds
*/
enum CS_SinkKind { CS_SINK_UNKNOWN = 0, CS_SINK_MJPEG = 2, CS_SINK_CV = 4 };
enum CS_SinkKind {
CS_SINK_UNKNOWN = 0,
CS_SINK_MJPEG = 2,
CS_SINK_CV = 4,
CS_SINK_RAW = 8
};
/**
* Listener event kinds
@@ -351,8 +355,6 @@ char** CS_GetHttpCameraUrls(CS_Source source, int* count, CS_Status* status);
* @defgroup cscore_opencv_source_cfunc OpenCV Source Functions
* @{
*/
void CS_PutSourceFrame(CS_Source source, struct CvMat* image,
CS_Status* status);
void CS_NotifySourceError(CS_Source source, const char* msg, CS_Status* status);
void CS_SetSourceConnected(CS_Source source, CS_Bool connected,
CS_Status* status);
@@ -415,9 +417,6 @@ int CS_GetMjpegServerPort(CS_Sink sink, CS_Status* status);
*/
void CS_SetSinkDescription(CS_Sink sink, const char* description,
CS_Status* status);
uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image, CS_Status* status);
uint64_t CS_GrabSinkFrameTimeout(CS_Sink sink, struct CvMat* image,
double timeout, CS_Status* status);
char* CS_GetSinkError(CS_Sink sink, CS_Status* status);
void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status);
/** @} */

View File

@@ -21,10 +21,6 @@
#include "cscore_c.h"
namespace cv {
class Mat;
} // namespace cv
namespace wpi {
class json;
} // namespace wpi
@@ -286,7 +282,6 @@ std::vector<std::string> GetHttpCameraUrls(CS_Source source, CS_Status* status);
* @defgroup cscore_opencv_source_func OpenCV Source Functions
* @{
*/
void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status);
void NotifySourceError(CS_Source source, const wpi::Twine& msg,
CS_Status* status);
void SetSourceConnected(CS_Source source, bool connected, CS_Status* status);
@@ -312,6 +307,7 @@ CS_Sink CreateCvSink(const wpi::Twine& name, CS_Status* status);
CS_Sink CreateCvSinkCallback(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame,
CS_Status* status);
/** @} */
/**
@@ -356,9 +352,6 @@ int GetMjpegServerPort(CS_Sink sink, CS_Status* status);
*/
void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
CS_Status* status);
uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status);
uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
CS_Status* status);
std::string GetSinkError(CS_Sink sink, CS_Status* status);
wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
CS_Status* status);
@@ -429,18 +422,4 @@ std::vector<std::string> GetNetworkInterfaces();
} // namespace cs
/**
* @defgroup cscore_cpp_opencv_special cscore C functions taking a cv::Mat*
*
* These are needed for specific interop implementations.
* @{
*/
extern "C" {
uint64_t CS_GrabSinkFrameCpp(CS_Sink sink, cv::Mat* image, CS_Status* status);
uint64_t CS_GrabSinkFrameTimeoutCpp(CS_Sink sink, cv::Mat* image,
double timeout, CS_Status* status);
void CS_PutSourceFrameCpp(CS_Source source, cv::Mat* image, CS_Status* status);
} // extern "C"
/** @} */
#endif // CSCORE_CSCORE_CPP_H_

View File

@@ -0,0 +1,205 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#ifndef CSCORE_CSCORE_CV_H_
#define CSCORE_CSCORE_CV_H_
#include "cscore_c.h"
#ifdef CSCORE_CSCORE_RAW_CV_H_
#error "Cannot include both cscore_cv.h and cscore_raw_cv.h in the same file"
#endif
#ifdef __cplusplus
#include "cscore_oo.h" // NOLINT(build/include_order)
#endif
#ifdef __cplusplus
extern "C" { // NOLINT(build/include_order)
#endif
struct CvMat;
void CS_PutSourceFrame(CS_Source source, struct CvMat* image,
CS_Status* status);
uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image, CS_Status* status);
uint64_t CS_GrabSinkFrameTimeout(CS_Sink sink, struct CvMat* image,
double timeout, CS_Status* status);
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef __cplusplus
#include "cscore_oo.h"
namespace cv {
class Mat;
} // namespace cv
namespace cs {
/**
* @defgroup cscore_cpp_opencv_special cscore C functions taking a cv::Mat*
*
* These are needed for specific interop implementations.
* @{
*/
extern "C" {
uint64_t CS_GrabSinkFrameCpp(CS_Sink sink, cv::Mat* image, CS_Status* status);
uint64_t CS_GrabSinkFrameTimeoutCpp(CS_Sink sink, cv::Mat* image,
double timeout, CS_Status* status);
void CS_PutSourceFrameCpp(CS_Source source, cv::Mat* image, CS_Status* status);
} // extern "C"
/** @} */
void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status);
uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status);
uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
CS_Status* status);
/**
* A source for user code to provide OpenCV images as video frames.
* These sources require the WPILib OpenCV builds.
* For an alternate OpenCV, include "cscore_raw_cv.h" instead, and
* include your Mat header before that header.
*/
class CvSource : public ImageSource {
public:
CvSource() = default;
/**
* Create an OpenCV source.
*
* @param name Source name (arbitrary unique identifier)
* @param mode Video mode being generated
*/
CvSource(const wpi::Twine& name, const VideoMode& mode);
/**
* Create an OpenCV source.
*
* @param name Source name (arbitrary unique identifier)
* @param pixelFormat Pixel format
* @param width width
* @param height height
* @param fps fps
*/
CvSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
int width, int height, int fps);
/**
* Put an OpenCV image and notify sinks.
*
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
* are supported. If the format, depth or channel order is different, use
* cv::Mat::convertTo() and/or cv::cvtColor() to convert it first.
*
* @param image OpenCV image
*/
void PutFrame(cv::Mat& image);
};
/**
* A sink for user code to accept video frames as OpenCV images.
* These sinks require the WPILib OpenCV builds.
* For an alternate OpenCV, include "cscore_raw_cv.h" instead, and
* include your Mat header before that header.
*/
class CvSink : public ImageSink {
public:
CvSink() = default;
/**
* Create a sink for accepting OpenCV images.
*
* <p>WaitForFrame() must be called on the created sink to get each new
* image.
*
* @param name Source name (arbitrary unique identifier)
*/
explicit CvSink(const wpi::Twine& name);
/**
* Create a sink for accepting OpenCV images in a separate thread.
*
* <p>A thread will be created that calls WaitForFrame() and calls the
* processFrame() callback each time a new frame arrives.
*
* @param name Source name (arbitrary unique identifier)
* @param processFrame Frame processing function; will be called with a
* time=0 if an error occurred. processFrame should call GetImage()
* or GetError() as needed, but should not call (except in very
* unusual circumstances) WaitForImage().
*/
CvSink(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame);
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after timeout seconds.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrame(cv::Mat& image, double timeout = 0.225) const;
/**
* Wait for the next frame and get the image. May block forever.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrameNoTimeout(cv::Mat& image) const;
};
inline CvSource::CvSource(const wpi::Twine& name, const VideoMode& mode) {
m_handle = CreateCvSource(name, mode, &m_status);
}
inline CvSource::CvSource(const wpi::Twine& name, VideoMode::PixelFormat format,
int width, int height, int fps) {
m_handle =
CreateCvSource(name, VideoMode{format, width, height, fps}, &m_status);
}
inline void CvSource::PutFrame(cv::Mat& image) {
m_status = 0;
PutSourceFrame(m_handle, image, &m_status);
}
inline CvSink::CvSink(const wpi::Twine& name) {
m_handle = CreateCvSink(name, &m_status);
}
inline CvSink::CvSink(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame) {
m_handle = CreateCvSinkCallback(name, processFrame, &m_status);
}
inline uint64_t CvSink::GrabFrame(cv::Mat& image, double timeout) const {
m_status = 0;
return GrabSinkFrameTimeout(m_handle, image, timeout, &m_status);
}
inline uint64_t CvSink::GrabFrameNoTimeout(cv::Mat& image) const {
m_status = 0;
return GrabSinkFrame(m_handle, image, &m_status);
}
} // namespace cs
#endif
#endif // CSCORE_CSCORE_CV_H_

View File

@@ -28,7 +28,7 @@ namespace cs {
*/
// Forward declarations so friend declarations work correctly
class CvSource;
class ImageSource;
class VideoEvent;
class VideoSink;
class VideoSource;
@@ -37,7 +37,7 @@ class VideoSource;
* A source or sink property.
*/
class VideoProperty {
friend class CvSource;
friend class ImageSource;
friend class VideoEvent;
friend class VideoSink;
friend class VideoSource;
@@ -617,43 +617,13 @@ class AxisCamera : public HttpCamera {
};
/**
* A source for user code to provide OpenCV images as video frames.
* A base class for single image providing sources.
*/
class CvSource : public VideoSource {
class ImageSource : public VideoSource {
protected:
ImageSource() = default;
public:
CvSource() = default;
/**
* Create an OpenCV source.
*
* @param name Source name (arbitrary unique identifier)
* @param mode Video mode being generated
*/
CvSource(const wpi::Twine& name, const VideoMode& mode);
/**
* Create an OpenCV source.
*
* @param name Source name (arbitrary unique identifier)
* @param pixelFormat Pixel format
* @param width width
* @param height height
* @param fps fps
*/
CvSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
int width, int height, int fps);
/**
* Put an OpenCV image and notify sinks.
*
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
* are supported. If the format, depth or channel order is different, use
* cv::Mat::convertTo() and/or cv::cvtColor() to convert it first.
*
* @param image OpenCV image
*/
void PutFrame(cv::Mat& image);
/**
* Signal sinks that an error has occurred. This should be called instead
* of NotifyFrame when an error occurs.
@@ -979,37 +949,13 @@ class MjpegServer : public VideoSink {
};
/**
* A sink for user code to accept video frames as OpenCV images.
* A base class for single image reading sinks.
*/
class CvSink : public VideoSink {
class ImageSink : public VideoSink {
protected:
ImageSink() = default;
public:
CvSink() = default;
/**
* Create a sink for accepting OpenCV images.
*
* <p>WaitForFrame() must be called on the created sink to get each new
* image.
*
* @param name Source name (arbitrary unique identifier)
*/
explicit CvSink(const wpi::Twine& name);
/**
* Create a sink for accepting OpenCV images in a separate thread.
*
* <p>A thread will be created that calls WaitForFrame() and calls the
* processFrame() callback each time a new frame arrives.
*
* @param name Source name (arbitrary unique identifier)
* @param processFrame Frame processing function; will be called with a
* time=0 if an error occurred. processFrame should call GetImage()
* or GetError() as needed, but should not call (except in very
* unusual circumstances) WaitForImage().
*/
CvSink(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame);
/**
* Set sink description.
*
@@ -1017,27 +963,6 @@ class CvSink : public VideoSink {
*/
void SetDescription(const wpi::Twine& description);
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after timeout seconds.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrame(cv::Mat& image, double timeout = 0.225) const;
/**
* Wait for the next frame and get the image. May block forever.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrameNoTimeout(cv::Mat& image) const;
/**
* Get error string. Call this if WaitForFrame() returns 0 to determine
* what the error is.

View File

@@ -378,37 +378,22 @@ inline AxisCamera::AxisCamera(const wpi::Twine& name,
std::initializer_list<T> hosts)
: HttpCamera(name, HostToUrl(hosts), kAxis) {}
inline CvSource::CvSource(const wpi::Twine& name, const VideoMode& mode) {
m_handle = CreateCvSource(name, mode, &m_status);
}
inline CvSource::CvSource(const wpi::Twine& name, VideoMode::PixelFormat format,
int width, int height, int fps) {
m_handle =
CreateCvSource(name, VideoMode{format, width, height, fps}, &m_status);
}
inline void CvSource::PutFrame(cv::Mat& image) {
m_status = 0;
PutSourceFrame(m_handle, image, &m_status);
}
inline void CvSource::NotifyError(const wpi::Twine& msg) {
inline void ImageSource::NotifyError(const wpi::Twine& msg) {
m_status = 0;
NotifySourceError(m_handle, msg, &m_status);
}
inline void CvSource::SetConnected(bool connected) {
inline void ImageSource::SetConnected(bool connected) {
m_status = 0;
SetSourceConnected(m_handle, connected, &m_status);
}
inline void CvSource::SetDescription(const wpi::Twine& description) {
inline void ImageSource::SetDescription(const wpi::Twine& description) {
m_status = 0;
SetSourceDescription(m_handle, description, &m_status);
}
inline VideoProperty CvSource::CreateProperty(const wpi::Twine& name,
inline VideoProperty ImageSource::CreateProperty(const wpi::Twine& name,
VideoProperty::Kind kind,
int minimum, int maximum,
int step, int defaultValue,
@@ -419,7 +404,7 @@ inline VideoProperty CvSource::CreateProperty(const wpi::Twine& name,
minimum, maximum, step, defaultValue, value, &m_status)};
}
inline VideoProperty CvSource::CreateIntegerProperty(const wpi::Twine& name,
inline VideoProperty ImageSource::CreateIntegerProperty(const wpi::Twine& name,
int minimum, int maximum,
int step, int defaultValue,
int value) {
@@ -429,7 +414,7 @@ inline VideoProperty CvSource::CreateIntegerProperty(const wpi::Twine& name,
minimum, maximum, step, defaultValue, value, &m_status)};
}
inline VideoProperty CvSource::CreateBooleanProperty(const wpi::Twine& name,
inline VideoProperty ImageSource::CreateBooleanProperty(const wpi::Twine& name,
bool defaultValue,
bool value) {
m_status = 0;
@@ -438,7 +423,7 @@ inline VideoProperty CvSource::CreateBooleanProperty(const wpi::Twine& name,
0, 1, 1, defaultValue ? 1 : 0, value ? 1 : 0, &m_status)};
}
inline VideoProperty CvSource::CreateStringProperty(const wpi::Twine& name,
inline VideoProperty ImageSource::CreateStringProperty(const wpi::Twine& name,
const wpi::Twine& value) {
m_status = 0;
auto prop = VideoProperty{CreateSourceProperty(
@@ -449,14 +434,14 @@ inline VideoProperty CvSource::CreateStringProperty(const wpi::Twine& name,
}
inline void CvSource::SetEnumPropertyChoices(
inline void ImageSource::SetEnumPropertyChoices(
const VideoProperty& property, wpi::ArrayRef<std::string> choices) {
m_status = 0;
SetSourceEnumPropertyChoices(m_handle, property.m_handle, choices, &m_status);
}
template <typename T>
inline void CvSource::SetEnumPropertyChoices(const VideoProperty& property,
inline void ImageSource::SetEnumPropertyChoices(const VideoProperty& property,
std::initializer_list<T> choices) {
std::vector<std::string> vec;
vec.reserve(choices.size());
@@ -575,36 +560,17 @@ inline void MjpegServer::SetDefaultCompression(int quality) {
quality, &m_status);
}
inline CvSink::CvSink(const wpi::Twine& name) {
m_handle = CreateCvSink(name, &m_status);
}
inline CvSink::CvSink(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame) {
m_handle = CreateCvSinkCallback(name, processFrame, &m_status);
}
inline void CvSink::SetDescription(const wpi::Twine& description) {
inline void ImageSink::SetDescription(const wpi::Twine& description) {
m_status = 0;
SetSinkDescription(m_handle, description, &m_status);
}
inline uint64_t CvSink::GrabFrame(cv::Mat& image, double timeout) const {
m_status = 0;
return GrabSinkFrameTimeout(m_handle, image, timeout, &m_status);
}
inline uint64_t CvSink::GrabFrameNoTimeout(cv::Mat& image) const {
m_status = 0;
return GrabSinkFrame(m_handle, image, &m_status);
}
inline std::string CvSink::GetError() const {
inline std::string ImageSink::GetError() const {
m_status = 0;
return GetSinkError(m_handle, &m_status);
}
inline void CvSink::SetEnabled(bool enabled) {
inline void ImageSink::SetEnabled(bool enabled) {
m_status = 0;
SetSinkEnabled(m_handle, enabled, &m_status);
}

View File

@@ -0,0 +1,234 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#ifndef CSCORE_CSCORE_RAW_H_
#define CSCORE_CSCORE_RAW_H_
#include "cscore_c.h"
#ifdef __cplusplus
#include "cscore_oo.h"
#endif
/**
* Raw Frame
*/
typedef struct CS_RawFrame {
char* data;
int dataLength;
int pixelFormat;
int width;
int height;
int totalData;
} CS_RawFrame;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup cscore_raw_cfunc Raw Image Functions
* @{
*/
void CS_AllocateRawFrameData(CS_RawFrame* frame, int requestedSize);
void CS_FreeRawFrameData(CS_RawFrame* frame);
uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct CS_RawFrame* rawImage,
CS_Status* status);
uint64_t CS_GrabRawSinkFrameTimeout(CS_Sink sink, struct CS_RawFrame* rawImage,
double timeout, CS_Status* status);
CS_Sink CS_CreateRawSink(const char* name, CS_Status* status);
CS_Sink CS_CreateRawSinkCallback(const char* name, void* data,
void (*processFrame)(void* data,
uint64_t time),
CS_Status* status);
void CS_PutRawSourceFrame(CS_Source source, const struct CS_RawFrame* image,
CS_Status* status);
CS_Source CS_CreateRawSource(const char* name, const CS_VideoMode* mode,
CS_Status* status);
/** @} */
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef __cplusplus
namespace cs {
struct RawFrame : public CS_RawFrame {
RawFrame() {
data = nullptr;
dataLength = 0;
pixelFormat = CS_PIXFMT_UNKNOWN;
width = 0;
height = 0;
totalData = 0;
}
~RawFrame() { CS_FreeRawFrameData(this); }
};
/**
* @defgroup cscore_raw_func Raw Image Functions
* @{
*/
CS_Source CreateRawSource(const wpi::Twine& name, const VideoMode& mode,
CS_Status* status);
CS_Sink CreateRawSink(const wpi::Twine& name, CS_Status* status);
CS_Sink CreateRawSinkCallback(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame,
CS_Status* status);
void PutSourceFrame(CS_Source source, const CS_RawFrame& image,
CS_Status* status);
uint64_t GrabSinkFrame(CS_Sink sink, CS_RawFrame& image, CS_Status* status);
uint64_t GrabSinkFrameTimeout(CS_Sink sink, CS_RawFrame& image, double timeout,
CS_Status* status);
/**
* A source for user code to provide video frames as raw bytes.
*
* This is a complex API, most cases should use CvSource.
*/
class RawSource : public ImageSource {
public:
RawSource() = default;
/**
* Create a raw frame source.
*
* @param name Source name (arbitrary unique identifier)
* @param mode Video mode being generated
*/
RawSource(const wpi::Twine& name, const VideoMode& mode);
/**
* Create a raw frame source.
*
* @param name Source name (arbitrary unique identifier)
* @param pixelFormat Pixel format
* @param width width
* @param height height
* @param fps fps
*/
RawSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
int width, int height, int fps);
protected:
/**
* Put a raw image and notify sinks.
*
* @param image raw frame image
*/
void PutFrame(RawFrame& image);
};
/**
* A sink for user code to accept video frames as raw bytes.
*
* This is a complex API, most cases should use CvSource.
*/
class RawSink : public ImageSink {
public:
RawSink() = default;
/**
* Create a sink for accepting raw images.
*
* <p>GrabFrame() must be called on the created sink to get each new
* image.
*
* @param name Source name (arbitrary unique identifier)
*/
explicit RawSink(const wpi::Twine& name);
/**
* Create a sink for accepting raws images in a separate thread.
*
* <p>A thread will be created that calls WaitForFrame() and calls the
* processFrame() callback each time a new frame arrives.
*
* @param name Source name (arbitrary unique identifier)
* @param processFrame Frame processing function; will be called with a
* time=0 if an error occurred. processFrame should call GetImage()
* or GetError() as needed, but should not call (except in very
* unusual circumstances) WaitForImage().
*/
RawSink(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame);
protected:
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after timeout seconds.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrame(RawFrame& image, double timeout = 0.225) const;
/**
* Wait for the next frame and get the image. May block forever.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrameNoTimeout(RawFrame& image) const;
};
inline RawSource::RawSource(const wpi::Twine& name, const VideoMode& mode) {
m_handle = CreateRawSource(name, mode, &m_status);
}
inline RawSource::RawSource(const wpi::Twine& name,
VideoMode::PixelFormat format, int width,
int height, int fps) {
m_handle =
CreateRawSource(name, VideoMode{format, width, height, fps}, &m_status);
}
inline void RawSource::PutFrame(RawFrame& image) {
m_status = 0;
PutSourceFrame(m_handle, image, &m_status);
}
inline RawSink::RawSink(const wpi::Twine& name) {
m_handle = CreateRawSink(name, &m_status);
}
inline RawSink::RawSink(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame) {
m_handle = CreateRawSinkCallback(name, processFrame, &m_status);
}
inline uint64_t RawSink::GrabFrame(RawFrame& image, double timeout) const {
m_status = 0;
return GrabSinkFrameTimeout(m_handle, image, timeout, &m_status);
}
inline uint64_t RawSink::GrabFrameNoTimeout(RawFrame& image) const {
m_status = 0;
return GrabSinkFrame(m_handle, image, &m_status);
}
} // namespace cs
/** @} */
#endif
#endif // CSCORE_CSCORE_RAW_H_

View File

@@ -0,0 +1,218 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#ifndef CSCORE_CSCORE_RAW_CV_H_
#define CSCORE_CSCORE_RAW_CV_H_
#ifdef CSCORE_CSCORE_CV_H_
#error "Cannot include both cscore_cv.h and cscore_raw_cv.h in the same file"
#endif
#include "cscore_raw.h"
namespace cs {
/**
* A source for using the raw frame API to provide opencv images.
*
* If you are using the WPILib OpenCV builds, do not use this, and
* instead include "cscore_cv.h" to get a more performant version.
*
* This is not dependent on any opencv binary ABI, and can be used
* with versions of OpenCV that are not 3. If using OpenCV 3, use
* CvSource.
*/
class RawCvSource : public RawSource {
public:
RawCvSource() = default;
/**
* Create a Raw OpenCV source.
*
* @param name Source name (arbitrary unique identifier)
* @param mode Video mode being generated
*/
RawCvSource(const wpi::Twine& name, const VideoMode& mode);
/**
* Create a Raw OpenCV source.
*
* @param name Source name (arbitrary unique identifier)
* @param pixelFormat Pixel format
* @param width width
* @param height height
* @param fps fps
*/
RawCvSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
int width, int height, int fps);
/**
* Put an OpenCV image and notify sinks.
*
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
* are supported. If the format, depth or channel order is different, use
* cv::Mat::convertTo() and/or cv::cvtColor() to convert it first.
*
* @param image OpenCV image
*/
void PutFrame(cv::Mat& image);
private:
RawFrame rawFrame;
};
/**
* A sink for user code to accept raw video frames as OpenCV images.
*
* If you are using the WPILib OpenCV builds, do not use this, and
* instead include "cscore_cv.h" to get a more performant version.
*
* This is not dependent on any opencv binary ABI, and can be used
* with versions of OpenCV that are not 3. If using OpenCV 3, use
* CvSink.
*/
class RawCvSink : public RawSink {
public:
RawCvSink() = default;
/**
* Create a sink for accepting OpenCV images.
*
* <p>WaitForFrame() must be called on the created sink to get each new
* image.
*
* @param name Source name (arbitrary unique identifier)
*/
explicit RawCvSink(const wpi::Twine& name);
/**
* Create a sink for accepting OpenCV images in a separate thread.
*
* <p>A thread will be created that calls WaitForFrame() and calls the
* processFrame() callback each time a new frame arrives.
*
* @param name Source name (arbitrary unique identifier)
* @param processFrame Frame processing function; will be called with a
* time=0 if an error occurred. processFrame should call GetImage()
* or GetError() as needed, but should not call (except in very
* unusual circumstances) WaitForImage().
*/
RawCvSink(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame);
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after timeout seconds.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrame(cv::Mat& image, double timeout = 0.225);
/**
* Wait for the next frame and get the image. May block forever.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrameNoTimeout(cv::Mat& image);
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after timeout seconds.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrameDirect(cv::Mat& image, double timeout = 0.225);
/**
* Wait for the next frame and get the image. May block forever.
* The provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
*/
uint64_t GrabFrameNoTimeoutDirect(cv::Mat& image);
private:
RawFrame rawFrame;
};
inline RawCvSource::RawCvSource(const wpi::Twine& name, const VideoMode& mode)
: RawSource{name, mode} {}
inline RawCvSource::RawCvSource(const wpi::Twine& name,
VideoMode::PixelFormat format, int width,
int height, int fps)
: RawSource{name, format, width, height, fps} {}
inline void RawCvSource::PutFrame(cv::Mat& image) {
m_status = 0;
rawFrame.data = reinterpret_cast<char*>(image.data);
rawFrame.width = image.cols;
rawFrame.height = image.rows;
rawFrame.totalData = image.total() * image.channels;
rawFrame.pixelFormat = image.channels == 3 ? CS_PIXFMT_BGR : CS_PIXFMT_GRAY;
PutSourceFrame(m_handle, rawFrame, &m_status);
}
inline RawCvSink::RawCvSink(const wpi::Twine& name) : RawSink{name} {}
inline RawCvSink::RawCvSink(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame)
: RawSink{name, processFrame} {}
inline uint64_t RawCvSink::GrabFrame(cv::Mat& image, double timeout) {
cv::Mat tmpMat;
auto retVal = GrabFrameDirect(tmpMat);
if (retVal <= 0) {
return retVal;
}
tmpMat.copyTo(image);
return retVal;
}
inline uint64_t RawCvSink::GrabFrameNoTimeout(cv::Mat& image) {
cv::Mat tmpMat;
auto retVal = GrabFrameNoTimeoutDirect(tmpMat);
if (retVal <= 0) {
return retVal;
}
tmpMat.copyTo(image);
return retVal;
}
inline uint64_t RawCvSink::GrabFrameDirect(cv::Mat& image, double timeout) {
rawFrame.height = 0;
rawFrame.width = 0;
rawFrame.pixelFormat = CS_PixelFormat::CS_PIXFMT_BGR;
m_status = RawSink::GrabFrame(rawFrame, timeout);
if (m_status <= 0) return m_status;
image = cv::Mat{rawFrame.height, rawFrame.width, CV_8UC3, rawFrame.data};
return m_status;
}
inline uint64_t RawCvSink::GrabFrameNoTimeoutDirect(cv::Mat& image) {
rawFrame.height = 0;
rawFrame.width = 0;
rawFrame.pixelFormat = CS_PixelFormat::CS_PIXFMT_BGR;
m_status = RawSink::GrabFrameNoTimeout(rawFrame);
if (m_status <= 0) return m_status;
image = cv::Mat{rawFrame.height, rawFrame.width, CV_8UC3, rawFrame.data};
return m_status;
}
} // namespace cs
#endif // CSCORE_CSCORE_RAW_CV_H_