mirror of
https://github.com/opencv/opencv.git
synced 2025-08-05 22:19:14 +08:00
Merge pull request #27226 from Kumataro:fix27225
imgproc: cvtColor: remove to copy edge pixels for COLOR_Bayer*_VNGs. #27226 Close https://github.com/opencv/opencv/issues/27225 Close https://github.com/opencv/opencv/issues/5089 Related https://github.com/opencv/opencv_extra/pull/1249 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
edccfa7961
commit
86a963cec9
@ -1041,9 +1041,11 @@ static void Bayer2RGB_( const Mat& srcmat, Mat& dstmat, int code )
|
||||
int dst_step = (int)(dstmat.step/sizeof(T));
|
||||
Size size = srcmat.size();
|
||||
int blue = (code == COLOR_BayerBG2BGR || code == COLOR_BayerGB2BGR ||
|
||||
code == COLOR_BayerBG2BGRA || code == COLOR_BayerGB2BGRA ) ? -1 : 1;
|
||||
code == COLOR_BayerBG2BGRA || code == COLOR_BayerGB2BGRA ||
|
||||
code == COLOR_BayerBG2BGR_VNG || code == COLOR_BayerGB2BGR_VNG) ? -1 : 1;
|
||||
int start_with_green = (code == COLOR_BayerGB2BGR || code == COLOR_BayerGR2BGR ||
|
||||
code == COLOR_BayerGB2BGRA || code == COLOR_BayerGR2BGRA);
|
||||
code == COLOR_BayerGB2BGRA || code == COLOR_BayerGR2BGRA ||
|
||||
code == COLOR_BayerGB2BGR_VNG || code == COLOR_BayerGR2BGR_VNG);
|
||||
|
||||
int dcn = dstmat.channels();
|
||||
size.height -= 2;
|
||||
@ -1073,8 +1075,20 @@ static void Bayer2RGB_( const Mat& srcmat, Mat& dstmat, int code )
|
||||
|
||||
/////////////////// Demosaicing using Variable Number of Gradients ///////////////////////
|
||||
|
||||
static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
|
||||
static void Bayer2RGB_VNG_8u( const Mat& _srcmat, Mat& dstmat, int code )
|
||||
{
|
||||
// for too small images use the simple interpolation algorithm
|
||||
if( MIN(_srcmat.size().width, _srcmat.size().height) < 8 )
|
||||
{
|
||||
Bayer2RGB_<uchar, SIMDBayerInterpolator_8u>( _srcmat, dstmat, code );
|
||||
return;
|
||||
}
|
||||
|
||||
// VNG uses a 5x5 filter to calculate the gradient around the target pixel.
|
||||
// To make it simple for edge pixels, 2 pixel paddings are added using reflection.
|
||||
cv::Mat srcmat;
|
||||
copyMakeBorder(_srcmat, srcmat, 2, 2, 2, 2, BORDER_REFLECT_101);
|
||||
|
||||
const uchar* bayer = srcmat.ptr();
|
||||
int bstep = (int)srcmat.step;
|
||||
uchar* dst = dstmat.ptr();
|
||||
@ -1084,24 +1098,15 @@ static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
|
||||
int blueIdx = code == COLOR_BayerBG2BGR_VNG || code == COLOR_BayerGB2BGR_VNG ? 0 : 2;
|
||||
bool greenCell0 = code != COLOR_BayerBG2BGR_VNG && code != COLOR_BayerRG2BGR_VNG;
|
||||
|
||||
// for too small images use the simple interpolation algorithm
|
||||
if( MIN(size.width, size.height) < 8 )
|
||||
{
|
||||
Bayer2RGB_<uchar, SIMDBayerInterpolator_8u>( srcmat, dstmat, code );
|
||||
return;
|
||||
}
|
||||
|
||||
const int brows = 3, bcn = 7;
|
||||
int N = size.width, N2 = N*2, N3 = N*3, N4 = N*4, N5 = N*5, N6 = N*6, N7 = N*7;
|
||||
int i, bufstep = N7*bcn;
|
||||
cv::AutoBuffer<ushort> _buf(bufstep*brows);
|
||||
ushort* buf = _buf.data();
|
||||
|
||||
bayer += bstep*2;
|
||||
|
||||
for( int y = 2; y < size.height - 4; y++ )
|
||||
for( int y = 2; y < size.height - 2; y++ )
|
||||
{
|
||||
uchar* dstrow = dst + dststep*y + 6;
|
||||
uchar* dstrow = dst + dststep*(y - 2); // srcmat has 2 pixel paddings, but dstmat has no padding.
|
||||
const uchar* srow;
|
||||
|
||||
for( int dy = (y == 2 ? -1 : 1); dy <= 1; dy++ )
|
||||
@ -1583,24 +1588,9 @@ static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
|
||||
}
|
||||
while( i < N - 2 );
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
dst[dststep*y + 5 - i] = dst[dststep*y + 8 - i];
|
||||
dst[dststep*y + (N - 2)*3 + i] = dst[dststep*y + (N - 3)*3 + i];
|
||||
}
|
||||
|
||||
greenCell0 = !greenCell0;
|
||||
blueIdx ^= 2;
|
||||
}
|
||||
|
||||
for( i = 0; i < size.width*3; i++ )
|
||||
{
|
||||
dst[i] = dst[i + dststep] = dst[i + dststep*2];
|
||||
dst[i + dststep*(size.height-4)] =
|
||||
dst[i + dststep*(size.height-3)] =
|
||||
dst[i + dststep*(size.height-2)] =
|
||||
dst[i + dststep*(size.height-1)] = dst[i + dststep*(size.height-5)];
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////// Edge-Aware Demosaicing //////////////////////////////////
|
||||
|
@ -1905,6 +1905,64 @@ TEST(Imgproc_ColorBayerVNG, regression)
|
||||
}
|
||||
}
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/5089
|
||||
// See https://github.com/opencv/opencv/issues/27225
|
||||
typedef tuple<cv::ColorConversionCodes, cv::ColorConversionCodes> VNGandINT;
|
||||
typedef testing::TestWithParam<VNGandINT> Imgproc_ColorBayerVNG_Codes;
|
||||
|
||||
TEST_P(Imgproc_ColorBayerVNG_Codes, regression27225)
|
||||
{
|
||||
const cv::ColorConversionCodes codeVNG = get<0>(GetParam());
|
||||
const int margin = (codeVNG == cv::COLOR_BayerGB2BGR_VNG || codeVNG == cv::COLOR_BayerGR2BGR_VNG)? 5 : 4;
|
||||
|
||||
cv::Mat in = cv::Mat::eye(16, 16, CV_8UC1) * 255;
|
||||
cv::resize(in, in, {}, 2, 2, cv::INTER_NEAREST);
|
||||
|
||||
cv::Mat out;
|
||||
EXPECT_NO_THROW(cv::cvtColor(in, out, codeVNG));
|
||||
|
||||
for(int iy=0; iy < out.size().height; iy++) {
|
||||
for(int ix=0; ix < out.size().width; ix++) {
|
||||
// Avoid to test around main diagonal pixels.
|
||||
if(cv::abs(ix - iy) < margin) {
|
||||
continue;
|
||||
}
|
||||
// Others should be completely black.
|
||||
const Vec3b pixel = out.at<Vec3b>(iy, ix);
|
||||
EXPECT_EQ(pixel[0], 0) << cv::format(" - iy = %d, ix = %d", iy, ix);
|
||||
EXPECT_EQ(pixel[1], 0) << cv::format(" - iy = %d, ix = %d", iy, ix);
|
||||
EXPECT_EQ(pixel[2], 0) << cv::format(" - iy = %d, ix = %d", iy, ix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(Imgproc_ColorBayerVNG_Codes, regression27225_small)
|
||||
{
|
||||
// for too small images use the simple interpolation algorithm
|
||||
const cv::ColorConversionCodes codeVNG = get<0>(GetParam());
|
||||
const cv::ColorConversionCodes codeINT = get<1>(GetParam());
|
||||
cv::Mat in = cv::Mat::eye(7, 7, CV_8UC1) * 255;
|
||||
|
||||
cv::Mat outVNG;
|
||||
EXPECT_NO_THROW(cv::cvtColor(in, outVNG, codeVNG));
|
||||
cv::Mat outINT;
|
||||
EXPECT_NO_THROW(cv::cvtColor(in, outINT, codeINT));
|
||||
|
||||
Mat diff;
|
||||
absdiff(outVNG, outINT, diff);
|
||||
|
||||
imwrite("outVNG.png", outVNG);
|
||||
imwrite("outINT.png", outINT);
|
||||
EXPECT_EQ(0, countNonZero(diff.reshape(1) > 1));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Imgproc_ColorBayerVNG_Codes,
|
||||
testing::Values(
|
||||
make_tuple(cv::COLOR_BayerBG2BGR_VNG, cv::COLOR_BayerBG2BGR),
|
||||
make_tuple(cv::COLOR_BayerGB2BGR_VNG, cv::COLOR_BayerGB2BGR),
|
||||
make_tuple(cv::COLOR_BayerRG2BGR_VNG, cv::COLOR_BayerRG2BGR),
|
||||
make_tuple(cv::COLOR_BayerGR2BGR_VNG, cv::COLOR_BayerGR2BGR)));
|
||||
|
||||
// creating Bayer pattern
|
||||
template <typename T, int depth>
|
||||
static void calculateBayerPattern(const Mat& src, Mat& bayer, const char* pattern)
|
||||
|
Loading…
Reference in New Issue
Block a user