[cscore] Add Y16 image support (#4702)

This commit is contained in:
Peter Johnson
2022-11-24 09:06:06 -08:00
committed by GitHub
parent 34ec89c041
commit b2d2924b72
11 changed files with 115 additions and 3 deletions

View File

@@ -217,7 +217,7 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
// Color convert
switch (pixelFormat) {
case VideoMode::kRGB565:
// If source is YUYV, UYVY, or Gray, need to convert to BGR first
// If source is YUYV, UYVY, Gray, or Y16, need to convert to BGR first
if (cur->pixelFormat == VideoMode::kYUYV) {
// Check to see if BGR version already exists...
if (Image* newImage =
@@ -242,9 +242,29 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
} else {
cur = ConvertGrayToBGR(cur);
}
} else if (cur->pixelFormat == VideoMode::kY16) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
} else if (Image* newImage = GetExistingImage(cur->width, cur->height,
VideoMode::kGray)) {
cur = ConvertGrayToBGR(newImage);
} else {
cur = ConvertGrayToBGR(ConvertY16ToGray(cur));
}
}
return ConvertBGRToRGB565(cur);
case VideoMode::kGray:
case VideoMode::kY16:
// If source is also grayscale, convert directly
if (pixelFormat == VideoMode::kGray &&
cur->pixelFormat == VideoMode::kY16) {
return ConvertY16ToGray(cur);
} else if (pixelFormat == VideoMode::kY16 &&
cur->pixelFormat == VideoMode::kGray) {
return ConvertGrayToY16(cur);
}
// If source is YUYV, UYVY, or RGB565, need to convert to BGR first
if (cur->pixelFormat == VideoMode::kYUYV) {
// Check to see if BGR version already exists...
@@ -271,7 +291,11 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
cur = ConvertRGB565ToBGR(cur);
}
}
return ConvertBGRToGray(cur);
cur = ConvertBGRToGray(cur);
if (pixelFormat == VideoMode::kY16) {
cur = ConvertGrayToY16(cur);
}
return cur;
case VideoMode::kBGR:
case VideoMode::kMJPEG:
if (cur->pixelFormat == VideoMode::kYUYV) {
@@ -286,6 +310,19 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
} else {
return ConvertGrayToMJPEG(cur, defaultJpegQuality);
}
} else if (cur->pixelFormat == VideoMode::kY16) {
// Check to see if Gray version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kGray)) {
cur = newImage;
} else {
cur = ConvertY16ToGray(cur);
}
if (pixelFormat == VideoMode::kBGR) {
return ConvertGrayToBGR(cur);
} else {
return ConvertGrayToMJPEG(cur, defaultJpegQuality);
}
}
break;
case VideoMode::kYUYV:
@@ -550,6 +587,50 @@ Image* Frame::ConvertGrayToMJPEG(Image* image, int quality) {
return rv;
}
Image* Frame::ConvertGrayToY16(Image* image) {
if (!image || image->pixelFormat != VideoMode::kGray) {
return nullptr;
}
// Allocate a Y16 image
auto newImage =
m_impl->source.AllocImage(VideoMode::kY16, image->width, image->height,
image->width * image->height * 2);
// Convert with linear scaling
image->AsMat().convertTo(newImage->AsMat(), CV_16U, 256);
// Save the result
Image* rv = newImage.release();
if (m_impl) {
std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
}
Image* Frame::ConvertY16ToGray(Image* image) {
if (!image || image->pixelFormat != VideoMode::kY16) {
return nullptr;
}
// Allocate a Grayscale image
auto newImage =
m_impl->source.AllocImage(VideoMode::kGray, image->width, image->height,
image->width * image->height);
// Scale min to 0 and max to 255
cv::normalize(image->AsMat(), newImage->AsMat(), 255, 0, cv::NORM_MINMAX);
// Save the result
Image* rv = newImage.release();
if (m_impl) {
std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
}
Image* Frame::GetImageImpl(int width, int height,
VideoMode::PixelFormat pixelFormat,
int requiredJpegQuality, int defaultJpegQuality) {

View File

@@ -202,6 +202,8 @@ class Frame {
Image* ConvertGrayToBGR(Image* image);
Image* ConvertBGRToMJPEG(Image* image, int quality);
Image* ConvertGrayToMJPEG(Image* image, int quality);
Image* ConvertGrayToY16(Image* image);
Image* ConvertY16ToGray(Image* image);
Image* GetImage(int width, int height, VideoMode::PixelFormat pixelFormat) {
if (pixelFormat == VideoMode::kMJPEG) {

View File

@@ -74,6 +74,7 @@ class Image {
switch (pixelFormat) {
case VideoMode::kYUYV:
case VideoMode::kRGB565:
case VideoMode::kY16:
case VideoMode::kUYVY:
type = CV_8UC2;
break;

View File

@@ -460,6 +460,9 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
case VideoMode::kGray:
os << "gray";
break;
case VideoMode::kY16:
os << "Y16";
break;
case VideoMode::kUYVY:
os << "UYVY";
break;
@@ -572,6 +575,9 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
case VideoMode::kGray:
os << "gray";
break;
case VideoMode::kY16:
os << "Y16";
break;
case VideoMode::kUYVY:
os << "UYVY";
break;
@@ -749,6 +755,7 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
case VideoMode::kUYVY:
case VideoMode::kRGB565:
case VideoMode::kYUYV:
case VideoMode::kY16:
default:
// Bad frame; sleep for 10 ms so we don't consume all processor time.
std::this_thread::sleep_for(std::chrono::milliseconds(10));

View File

@@ -26,6 +26,7 @@ void RawSourceImpl::PutFrame(const CS_RawFrame& image) {
switch (image.pixelFormat) {
case VideoMode::kYUYV:
case VideoMode::kRGB565:
case VideoMode::kY16:
case VideoMode::kUYVY:
type = CV_8UC2;
break;

View File

@@ -198,6 +198,8 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
mode.pixelFormat = cs::VideoMode::kBGR;
} else if (wpi::equals_lower(str, "gray")) {
mode.pixelFormat = cs::VideoMode::kGray;
} else if (wpi::equals_lower(str, "y16")) {
mode.pixelFormat = cs::VideoMode::kY16;
} else if (wpi::equals_lower(str, "uyvy")) {
mode.pixelFormat = cs::VideoMode::kUYVY;
} else {
@@ -362,6 +364,9 @@ wpi::json SourceImpl::GetConfigJsonObject(CS_Status* status) {
case VideoMode::kGray:
pixelFormat = "gray";
break;
case VideoMode::kY16:
pixelFormat = "y16";
break;
case VideoMode::kUYVY:
pixelFormat = "uyvy";
break;