1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 23:33:05 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2026-06-01 13:21:19 +03:00
30 changed files with 1245 additions and 152 deletions
+17
View File
@@ -2,10 +2,27 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_IMGCODECS_APPLE_CONVERSIONS_H
#define OPENCV_IMGCODECS_APPLE_CONVERSIONS_H
#include "opencv2/core.hpp"
#import <Accelerate/Accelerate.h>
#include <TargetConditionals.h>
#ifdef HAVE_AVFOUNDATION
#import <AVFoundation/AVFoundation.h>
#endif
#if TARGET_OS_IPHONE || (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080)
#import <ImageIO/ImageIO.h>
#else
#import <ApplicationServices/ApplicationServices.h>
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
#endif
CV_EXPORTS CGImageRef MatToCGImage(const cv::Mat& image) CF_RETURNS_RETAINED;
CV_EXPORTS void CGImageToMat(const CGImageRef image, cv::Mat& m, bool alphaExist);
#endif // OPENCV_IMGCODECS_APPLE_CONVERSIONS_H
@@ -5,6 +5,12 @@
#include "apple_conversions.h"
#include "precomp.hpp"
#import <Foundation/Foundation.h>
#ifndef __bridge
#define __bridge
#endif
CGImageRef MatToCGImage(const cv::Mat& image) {
NSData *data = [NSData dataWithBytes:image.data
length:image.step.p[0] * image.rows];
+14 -2
View File
@@ -61,10 +61,22 @@ bool SunRasterDecoder::readHeader()
int palSize = (m_bpp > 0 && m_bpp <= 8) ? (3*(1 << m_bpp)) : 0;
m_strm.skip( 4 );
m_encoding = (SunRasType)m_strm.getDWord();
m_maptype = (SunRasMapType)m_strm.getDWord();
// Read as plain integers first; validate before casting to enum types.
// Casting an out-of-range integer directly to an enum with no fixed
// underlying type is undefined behavior (C++11 §7.2/8). Reject invalid
// values early so no downstream code ever touches an ill-formed enum.
const int raw_encoding = (int)m_strm.getDWord();
const int raw_maptype = (int)m_strm.getDWord();
m_maplength = m_strm.getDWord();
if (raw_encoding < RAS_OLD || raw_encoding > RAS_FORMAT_RGB)
return false;
if (raw_maptype < RMT_NONE || raw_maptype > RMT_EQUAL_RGB)
return false;
m_encoding = (SunRasType)raw_encoding;
m_maptype = (SunRasMapType)raw_maptype;
if( m_width > 0 && m_height > 0 &&
(m_bpp == 1 || m_bpp == 8 || m_bpp == 24 || m_bpp == 32) &&
(m_encoding == RAS_OLD || m_encoding == RAS_STANDARD ||
+3 -1
View File
@@ -13,9 +13,11 @@ NSImage* MatToNSImage(const cv::Mat& image) {
CGImageRef imageRef = MatToCGImage(image);
// Getting NSImage from CGImage
NSImage *nsImage = [[NSImage alloc] initWithCGImage:imageRef size:CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef))];
NSSize imageSize = NSMakeSize(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
NSImage *nsImage = [[NSImage alloc] initWithCGImage:imageRef size:imageSize];
CGImageRelease(imageRef);
return nsImage;
}
+138
View File
@@ -0,0 +1,138 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
// Regression tests for the Sun Raster decoder (grfmt_sunras.cpp).
// These tests guard against:
// - UBSan "load of invalid enum value" in SunRasterDecoder::readHeader()
// (see https://github.com/opencv/opencv/issues/29150)
// - Out-of-range SunRasType / SunRasMapType values causing UB via unchecked C-cast
#include "test_precomp.hpp"
#include <vector>
namespace opencv_test { namespace {
// ---------------------------------------------------------------------------
// Helper: build a minimal Sun Raster byte buffer with caller-supplied fields.
// Sun Raster header layout (all fields big-endian, 32-bit):
// [0] magic = 0x59a66a95
// [4] width
// [8] height
// [12] depth (bits-per-pixel)
// [16] length (image data length, may be 0 for RAS_OLD)
// [20] ras_type (SunRasType)
// [24] maptype (SunRasMapType)
// [28] maplength
// ---------------------------------------------------------------------------
static std::vector<uint8_t> makeSunRasHeader(
uint32_t width, uint32_t height, uint32_t depth,
uint32_t length, uint32_t ras_type, uint32_t maptype, uint32_t maplength)
{
std::vector<uint8_t> buf(32);
auto put32 = [&](size_t off, uint32_t v) {
buf[off+0] = (v >> 24) & 0xff;
buf[off+1] = (v >> 16) & 0xff;
buf[off+2] = (v >> 8) & 0xff;
buf[off+3] = (v ) & 0xff;
};
put32( 0, 0x59a66a95u); // magic
put32( 4, width);
put32( 8, height);
put32(12, depth);
put32(16, length);
put32(20, ras_type);
put32(24, maptype);
put32(28, maplength);
return buf;
}
// ---------------------------------------------------------------------------
// Crash / UBSan regression — issue #29150
// Feeding an invalid maptype value (34077 / 0x851d) must NOT trigger UB;
// imdecode must return an empty Mat gracefully.
// ---------------------------------------------------------------------------
TEST(Imgcodecs_SunRaster, invalid_maptype_returns_empty_29150)
{
// Crafted header from the original bug report:
// magic=0x59a66a95, width=0x10101, height=0x10000, depth=1, length=0x1000000
// ras_type=0 (RAS_OLD, valid), maptype=0x851d (34077, INVALID)
const std::vector<uint8_t> image_data = {
0x59,0xa6,0x6a,0x95, 0x01,0x01,0x00,0x00,
0x00,0x01,0x00,0x00, 0x00,0x00,0x00,0x01,
0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x85,0x1d, 0xae,0x5b,0x8d,0xd5,
0x9c,0x25,0x22,0x41, 0x51,0x92,0x13,0x14,0x33
};
cv::Mat result;
ASSERT_NO_THROW(result = cv::imdecode(image_data, cv::IMREAD_REDUCED_GRAYSCALE_2));
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for invalid maptype";
}
// Invalid ras_type (value well outside [0,3]) must be rejected cleanly.
TEST(Imgcodecs_SunRaster, invalid_rastype_returns_empty)
{
auto buf = makeSunRasHeader(/*w*/8, /*h*/8, /*depth*/8,
/*len*/0, /*ras_type*/0xFFFF, /*maptype*/0, /*mapllen*/0);
cv::Mat result;
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for invalid ras_type";
}
// maptype = 2 is outside [0,1] (only RMT_NONE=0, RMT_EQUAL_RGB=1 are defined).
TEST(Imgcodecs_SunRaster, maptype_2_returns_empty)
{
auto buf = makeSunRasHeader(8, 8, 8, 0, /*ras_type*/0, /*maptype*/2, 0);
cv::Mat result;
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for maptype=2";
}
// maptype = UINT32_MAX is also invalid.
TEST(Imgcodecs_SunRaster, maptype_max_returns_empty)
{
auto buf = makeSunRasHeader(8, 8, 8, 0, 0, 0xFFFFFFFFu, 0);
cv::Mat result;
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for maptype=UINT_MAX";
}
// A truncated buffer (shorter than the 32-byte header) must not crash.
TEST(Imgcodecs_SunRaster, truncated_header_returns_empty)
{
// Only 16 bytes — header read will run out of data.
const std::vector<uint8_t> buf = {
0x59,0xa6,0x6a,0x95, 0x00,0x00,0x00,0x08,
0x00,0x00,0x00,0x08, 0x00,0x00,0x00,0x08
};
cv::Mat result;
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
EXPECT_TRUE(result.empty()) << "imdecode must return empty Mat for truncated header";
}
// ---------------------------------------------------------------------------
// Sanity: a well-formed 8-bpp grayscale Sun Raster (RMT_NONE) still decodes.
// We build the full header + pixel data manually so the test has no file I/O.
// ---------------------------------------------------------------------------
TEST(Imgcodecs_SunRaster, valid_8bpp_grayscale_decodes)
{
const int W = 4, H = 4;
// RAS_OLD(0), maptype=RMT_NONE(0), maplength=0
auto buf = makeSunRasHeader(W, H, 8, W*H, 0, 0, 0);
// Sun Raster rows are padded to 16-bit boundary.
// W=4: row_bytes = 4 (already even), no padding needed.
for (int i = 0; i < W * H; ++i)
buf.push_back(static_cast<uint8_t>(i * 16)); // arbitrary gray values
cv::Mat result;
ASSERT_NO_THROW(result = cv::imdecode(buf, cv::IMREAD_GRAYSCALE));
EXPECT_FALSE(result.empty()) << "imdecode must succeed for a valid 8-bpp Sun Raster";
EXPECT_EQ(result.cols, W);
EXPECT_EQ(result.rows, H);
EXPECT_EQ(result.type(), CV_8UC1);
}
}} // namespace opencv_test
+6
View File
@@ -45,6 +45,12 @@ PERF_TEST_P_ACCUMULATE(Accumulate, MAT_TYPES_ACCUMLATE,
PERF_TEST_P_ACCUMULATE(AccumulateMask, MAT_TYPES_ACCUMLATE_C,
PERF_ACCUMULATE_MASK_INIT(CV_32FC), accumulate(src1, dst, mask))
PERF_TEST_P_ACCUMULATE(AccumulateMask32FC4, CV_32FC4,
PERF_ACCUMULATE_MASK_INIT(CV_32FC), accumulate(src1, dst, mask))
PERF_TEST_P_ACCUMULATE(AccumulateMask8UC4To32FC4, CV_8UC4,
PERF_ACCUMULATE_MASK_INIT(CV_32FC), accumulate(src1, dst, mask))
PERF_TEST_P_ACCUMULATE(AccumulateDouble, MAT_TYPES_ACCUMLATE_D,
PERF_ACCUMULATE_INIT(CV_64FC), accumulate(src1, dst))
+265 -101
View File
@@ -317,79 +317,183 @@ void acc_simd_(const uchar* src, float* dst, const uchar* mask, int len, int cn)
}
else
{
v_uint8 v_0 = vx_setall_u8(0);
if (cn == 1)
if (x <= len - cVectorWidth)
{
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
v_uint8 v_0 = vx_setall_u8(0);
if (cn == 1)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_not(v_eq(v_0, v_mask));
v_uint8 v_src = vx_load(src + x);
v_src = v_and(v_src, v_mask);
v_uint16 v_src0, v_src1;
v_expand(v_src, v_src0, v_src1);
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_ne(v_0, v_mask);
v_uint8 v_src = vx_load(src + x);
v_src = v_and(v_src, v_mask);
v_uint16 v_src0, v_src1;
v_expand(v_src, v_src0, v_src1);
v_uint32 v_src00, v_src01, v_src10, v_src11;
v_expand(v_src0, v_src00, v_src01);
v_expand(v_src1, v_src10, v_src11);
v_uint32 v_src00, v_src01, v_src10, v_src11;
v_expand(v_src0, v_src00, v_src01);
v_expand(v_src1, v_src10, v_src11);
v_store(dst + x, v_add(vx_load(dst + x), v_cvt_f32(v_reinterpret_as_s32(v_src00))));
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_cvt_f32(v_reinterpret_as_s32(v_src01))));
v_store(dst + x + step * 2, v_add(vx_load(dst + x + step * 2), v_cvt_f32(v_reinterpret_as_s32(v_src10))));
v_store(dst + x + step * 3, v_add(vx_load(dst + x + step * 3), v_cvt_f32(v_reinterpret_as_s32(v_src11))));
v_store(dst + x, v_add(vx_load(dst + x), v_cvt_f32(v_reinterpret_as_s32(v_src00))));
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_cvt_f32(v_reinterpret_as_s32(v_src01))));
v_store(dst + x + step * 2, v_add(vx_load(dst + x + step * 2), v_cvt_f32(v_reinterpret_as_s32(v_src10))));
v_store(dst + x + step * 3, v_add(vx_load(dst + x + step * 3), v_cvt_f32(v_reinterpret_as_s32(v_src11))));
}
}
}
else if (cn == 3)
{
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
else if (cn == 3)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_not(v_eq(v_0, v_mask));
v_uint8 v_src0, v_src1, v_src2;
v_load_deinterleave(src + (x * cn), v_src0, v_src1, v_src2);
v_src0 = v_and(v_src0, v_mask);
v_src1 = v_and(v_src1, v_mask);
v_src2 = v_and(v_src2, v_mask);
v_uint16 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
v_expand(v_src0, v_src00, v_src01);
v_expand(v_src1, v_src10, v_src11);
v_expand(v_src2, v_src20, v_src21);
for ( ; x <= len - cVectorWidth; x += cVectorWidth)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_ne(v_0, v_mask);
v_uint8 v_src0, v_src1, v_src2;
v_load_deinterleave(src + (x * cn), v_src0, v_src1, v_src2);
v_src0 = v_and(v_src0, v_mask);
v_src1 = v_and(v_src1, v_mask);
v_src2 = v_and(v_src2, v_mask);
v_uint16 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
v_expand(v_src0, v_src00, v_src01);
v_expand(v_src1, v_src10, v_src11);
v_expand(v_src2, v_src20, v_src21);
v_uint32 v_src000, v_src001, v_src010, v_src011;
v_uint32 v_src100, v_src101, v_src110, v_src111;
v_uint32 v_src200, v_src201, v_src210, v_src211;
v_expand(v_src00, v_src000, v_src001);
v_expand(v_src01, v_src010, v_src011);
v_expand(v_src10, v_src100, v_src101);
v_expand(v_src11, v_src110, v_src111);
v_expand(v_src20, v_src200, v_src201);
v_expand(v_src21, v_src210, v_src211);
v_uint32 v_src000, v_src001, v_src010, v_src011;
v_uint32 v_src100, v_src101, v_src110, v_src111;
v_uint32 v_src200, v_src201, v_src210, v_src211;
v_expand(v_src00, v_src000, v_src001);
v_expand(v_src01, v_src010, v_src011);
v_expand(v_src10, v_src100, v_src101);
v_expand(v_src11, v_src110, v_src111);
v_expand(v_src20, v_src200, v_src201);
v_expand(v_src21, v_src210, v_src211);
v_float32 v_dst000, v_dst001, v_dst010, v_dst011;
v_float32 v_dst100, v_dst101, v_dst110, v_dst111;
v_float32 v_dst200, v_dst201, v_dst210, v_dst211;
v_load_deinterleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
v_load_deinterleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
v_load_deinterleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
v_load_deinterleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
v_float32 v_dst000, v_dst001, v_dst010, v_dst011;
v_float32 v_dst100, v_dst101, v_dst110, v_dst111;
v_float32 v_dst200, v_dst201, v_dst210, v_dst211;
v_load_deinterleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
v_load_deinterleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
v_load_deinterleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
v_load_deinterleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
v_dst000 = v_add(v_dst000, v_cvt_f32(v_reinterpret_as_s32(v_src000)));
v_dst100 = v_add(v_dst100, v_cvt_f32(v_reinterpret_as_s32(v_src100)));
v_dst200 = v_add(v_dst200, v_cvt_f32(v_reinterpret_as_s32(v_src200)));
v_dst001 = v_add(v_dst001, v_cvt_f32(v_reinterpret_as_s32(v_src001)));
v_dst101 = v_add(v_dst101, v_cvt_f32(v_reinterpret_as_s32(v_src101)));
v_dst201 = v_add(v_dst201, v_cvt_f32(v_reinterpret_as_s32(v_src201)));
v_dst010 = v_add(v_dst010, v_cvt_f32(v_reinterpret_as_s32(v_src010)));
v_dst110 = v_add(v_dst110, v_cvt_f32(v_reinterpret_as_s32(v_src110)));
v_dst210 = v_add(v_dst210, v_cvt_f32(v_reinterpret_as_s32(v_src210)));
v_dst011 = v_add(v_dst011, v_cvt_f32(v_reinterpret_as_s32(v_src011)));
v_dst111 = v_add(v_dst111, v_cvt_f32(v_reinterpret_as_s32(v_src111)));
v_dst211 = v_add(v_dst211, v_cvt_f32(v_reinterpret_as_s32(v_src211)));
v_dst000 = v_add(v_dst000, v_cvt_f32(v_reinterpret_as_s32(v_src000)));
v_dst100 = v_add(v_dst100, v_cvt_f32(v_reinterpret_as_s32(v_src100)));
v_dst200 = v_add(v_dst200, v_cvt_f32(v_reinterpret_as_s32(v_src200)));
v_dst001 = v_add(v_dst001, v_cvt_f32(v_reinterpret_as_s32(v_src001)));
v_dst101 = v_add(v_dst101, v_cvt_f32(v_reinterpret_as_s32(v_src101)));
v_dst201 = v_add(v_dst201, v_cvt_f32(v_reinterpret_as_s32(v_src201)));
v_dst010 = v_add(v_dst010, v_cvt_f32(v_reinterpret_as_s32(v_src010)));
v_dst110 = v_add(v_dst110, v_cvt_f32(v_reinterpret_as_s32(v_src110)));
v_dst210 = v_add(v_dst210, v_cvt_f32(v_reinterpret_as_s32(v_src210)));
v_dst011 = v_add(v_dst011, v_cvt_f32(v_reinterpret_as_s32(v_src011)));
v_dst111 = v_add(v_dst111, v_cvt_f32(v_reinterpret_as_s32(v_src111)));
v_dst211 = v_add(v_dst211, v_cvt_f32(v_reinterpret_as_s32(v_src211)));
v_store_interleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
v_store_interleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
v_store_interleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
v_store_interleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
v_store_interleave(dst + (x * cn), v_dst000, v_dst100, v_dst200);
v_store_interleave(dst + ((x + step) * cn), v_dst001, v_dst101, v_dst201);
v_store_interleave(dst + ((x + step * 2) * cn), v_dst010, v_dst110, v_dst210);
v_store_interleave(dst + ((x + step * 3) * cn), v_dst011, v_dst111, v_dst211);
}
}
else if (cn == 4)
{
v_uint8 v_zero = vx_setzero_u8();
for (; x <= len - cVectorWidth; x += cVectorWidth)
{
v_uint8 v_mask = vx_load(mask + x);
v_mask = v_ne(v_mask, v_zero);
v_uint8 v_src0, v_src1, v_src2, v_src3;
v_load_deinterleave(src + x * cn,
v_src0, v_src1, v_src2, v_src3);
v_src0 = v_and(v_src0, v_mask);
v_src1 = v_and(v_src1, v_mask);
v_src2 = v_and(v_src2, v_mask);
v_src3 = v_and(v_src3, v_mask);
v_uint16 v_src0_u16_0, v_src0_u16_1;
v_uint16 v_src1_u16_0, v_src1_u16_1;
v_uint16 v_src2_u16_0, v_src2_u16_1;
v_uint16 v_src3_u16_0, v_src3_u16_1;
v_expand(v_src0, v_src0_u16_0, v_src0_u16_1);
v_expand(v_src1, v_src1_u16_0, v_src1_u16_1);
v_expand(v_src2, v_src2_u16_0, v_src2_u16_1);
v_expand(v_src3, v_src3_u16_0, v_src3_u16_1);
v_uint32 v_src0_u32_0, v_src0_u32_1, v_src0_u32_2, v_src0_u32_3;
v_uint32 v_src1_u32_0, v_src1_u32_1, v_src1_u32_2, v_src1_u32_3;
v_uint32 v_src2_u32_0, v_src2_u32_1, v_src2_u32_2, v_src2_u32_3;
v_uint32 v_src3_u32_0, v_src3_u32_1, v_src3_u32_2, v_src3_u32_3;
v_expand(v_src0_u16_0, v_src0_u32_0, v_src0_u32_1);
v_expand(v_src0_u16_1, v_src0_u32_2, v_src0_u32_3);
v_expand(v_src1_u16_0, v_src1_u32_0, v_src1_u32_1);
v_expand(v_src1_u16_1, v_src1_u32_2, v_src1_u32_3);
v_expand(v_src2_u16_0, v_src2_u32_0, v_src2_u32_1);
v_expand(v_src2_u16_1, v_src2_u32_2, v_src2_u32_3);
v_expand(v_src3_u16_0, v_src3_u32_0, v_src3_u32_1);
v_expand(v_src3_u16_1, v_src3_u32_2, v_src3_u32_3);
v_float32 v_src0_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_0));
v_float32 v_src0_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_1));
v_float32 v_src0_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_2));
v_float32 v_src0_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src0_u32_3));
v_float32 v_src1_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_0));
v_float32 v_src1_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_1));
v_float32 v_src1_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_2));
v_float32 v_src1_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src1_u32_3));
v_float32 v_src2_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_0));
v_float32 v_src2_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_1));
v_float32 v_src2_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_2));
v_float32 v_src2_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src2_u32_3));
v_float32 v_src3_f0 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_0));
v_float32 v_src3_f1 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_1));
v_float32 v_src3_f2 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_2));
v_float32 v_src3_f3 = v_cvt_f32(v_reinterpret_as_s32(v_src3_u32_3));
v_float32 v_dst0, v_dst1, v_dst2, v_dst3;
v_load_deinterleave(dst + x * cn, v_dst0, v_dst1, v_dst2, v_dst3);
v_store_interleave(dst + x * cn,
v_add(v_dst0, v_src0_f0),
v_add(v_dst1, v_src1_f0),
v_add(v_dst2, v_src2_f0),
v_add(v_dst3, v_src3_f0));
v_load_deinterleave(dst + (x + step) * cn, v_dst0, v_dst1, v_dst2, v_dst3);
v_store_interleave(dst + (x + step) * cn,
v_add(v_dst0, v_src0_f1),
v_add(v_dst1, v_src1_f1),
v_add(v_dst2, v_src2_f1),
v_add(v_dst3, v_src3_f1));
v_load_deinterleave(dst + (x + 2 * step) * cn, v_dst0, v_dst1, v_dst2, v_dst3);
v_store_interleave(dst + (x + 2 * step) * cn,
v_add(v_dst0, v_src0_f2),
v_add(v_dst1, v_src1_f2),
v_add(v_dst2, v_src2_f2),
v_add(v_dst3, v_src3_f2));
v_load_deinterleave(dst + (x + 3 * step) * cn, v_dst0, v_dst1, v_dst2, v_dst3);
v_store_interleave(dst + (x + 3 * step) * cn,
v_add(v_dst0, v_src0_f3),
v_add(v_dst1, v_src1_f3),
v_add(v_dst2, v_src2_f3),
v_add(v_dst3, v_src3_f3));
}
}
}
}
@@ -500,49 +604,109 @@ void acc_simd_(const float* src, float* dst, const uchar* mask, int len, int cn)
}
else
{
v_float32 v_0 = vx_setzero_f32();
if (cn == 1)
if (x <= len - cVectorWidth)
{
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
v_float32 v_0 = vx_setzero_f32();
if (cn == 1)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
v_store(dst + x, v_add(vx_load(dst + x), v_and(vx_load(src + x), v_mask0)));
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_and(vx_load(src + x + step), v_mask1)));
v_store(dst + x, v_add(vx_load(dst + x), v_and(vx_load(src + x), v_mask0)));
v_store(dst + x + step, v_add(vx_load(dst + x + step), v_and(vx_load(src + x + step), v_mask1)));
}
}
else if (cn == 3)
{
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
v_float32 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
v_load_deinterleave(src + x * cn, v_src00, v_src10, v_src20);
v_load_deinterleave(src + (x + step) * cn, v_src01, v_src11, v_src21);
v_src00 = v_and(v_src00, v_mask0);
v_src01 = v_and(v_src01, v_mask1);
v_src10 = v_and(v_src10, v_mask0);
v_src11 = v_and(v_src11, v_mask1);
v_src20 = v_and(v_src20, v_mask0);
v_src21 = v_and(v_src21, v_mask1);
v_float32 v_dst00, v_dst01, v_dst10, v_dst11, v_dst20, v_dst21;
v_load_deinterleave(dst + x * cn, v_dst00, v_dst10, v_dst20);
v_load_deinterleave(dst + (x + step) * cn, v_dst01, v_dst11, v_dst21);
v_store_interleave(dst + x * cn, v_add(v_dst00, v_src00), v_add(v_dst10, v_src10), v_add(v_dst20, v_src20));
v_store_interleave(dst + (x + step) * cn, v_add(v_dst01, v_src01), v_add(v_dst11, v_src11), v_add(v_dst21, v_src21));
}
}
else if (cn == 4)
{
for (; x <= len - cVectorWidth; x += cVectorWidth)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_ne(v_masku320, v_reinterpret_as_u32(v_0)));
v_float32 v_mask1 = v_reinterpret_as_f32(v_ne(v_masku321, v_reinterpret_as_u32(v_0)));
v_float32 v_src00, v_src01;
v_float32 v_src10, v_src11;
v_float32 v_src20, v_src21;
v_float32 v_src30, v_src31;
v_load_deinterleave(src + x * cn,
v_src00, v_src10, v_src20, v_src30);
v_load_deinterleave(src + (x + step) * cn,
v_src01, v_src11, v_src21, v_src31);
v_src00 = v_and(v_src00, v_mask0);
v_src10 = v_and(v_src10, v_mask0);
v_src20 = v_and(v_src20, v_mask0);
v_src30 = v_and(v_src30, v_mask0);
v_src01 = v_and(v_src01, v_mask1);
v_src11 = v_and(v_src11, v_mask1);
v_src21 = v_and(v_src21, v_mask1);
v_src31 = v_and(v_src31, v_mask1);
v_float32 v_dst00, v_dst01;
v_float32 v_dst10, v_dst11;
v_float32 v_dst20, v_dst21;
v_float32 v_dst30, v_dst31;
v_load_deinterleave(dst + x * cn, v_dst00, v_dst10, v_dst20, v_dst30);
v_load_deinterleave(dst + (x + step) * cn, v_dst01, v_dst11, v_dst21, v_dst31);
v_store_interleave(dst + x * cn,
v_add(v_dst00, v_src00),
v_add(v_dst10, v_src10),
v_add(v_dst20, v_src20),
v_add(v_dst30, v_src30));
v_store_interleave(dst + (x + step) * cn,
v_add(v_dst01, v_src01),
v_add(v_dst11, v_src11),
v_add(v_dst21, v_src21),
v_add(v_dst31, v_src31));
}
}
}
else if (cn == 3)
{
for ( ; x <= len - cVectorWidth ; x += cVectorWidth)
{
v_uint16 v_masku16 = vx_load_expand(mask + x);
v_uint32 v_masku320, v_masku321;
v_expand(v_masku16, v_masku320, v_masku321);
v_float32 v_mask0 = v_reinterpret_as_f32(v_not(v_eq(v_masku320, v_reinterpret_as_u32(v_0))));
v_float32 v_mask1 = v_reinterpret_as_f32(v_not(v_eq(v_masku321, v_reinterpret_as_u32(v_0))));
v_float32 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21;
v_load_deinterleave(src + x * cn, v_src00, v_src10, v_src20);
v_load_deinterleave(src + (x + step) * cn, v_src01, v_src11, v_src21);
v_src00 = v_and(v_src00, v_mask0);
v_src01 = v_and(v_src01, v_mask1);
v_src10 = v_and(v_src10, v_mask0);
v_src11 = v_and(v_src11, v_mask1);
v_src20 = v_and(v_src20, v_mask0);
v_src21 = v_and(v_src21, v_mask1);
v_float32 v_dst00, v_dst01, v_dst10, v_dst11, v_dst20, v_dst21;
v_load_deinterleave(dst + x * cn, v_dst00, v_dst10, v_dst20);
v_load_deinterleave(dst + (x + step) * cn, v_dst01, v_dst11, v_dst21);
v_store_interleave(dst + x * cn, v_add(v_dst00, v_src00), v_add(v_dst10, v_src10), v_add(v_dst20, v_src20));
v_store_interleave(dst + (x + step) * cn, v_add(v_dst01, v_src01), v_add(v_dst11, v_src11), v_add(v_dst21, v_src21));
}
}
}
#endif // CV_SIMD
acc_general_(src, dst, mask, len, cn, x);
@@ -3106,4 +3270,4 @@ CV_CPU_OPTIMIZATION_NAMESPACE_END
} // namespace cv
///* End of file. */
///* End of file. */
+1 -1
View File
@@ -649,7 +649,7 @@ void cv::findContours(InputArray _image,
}
// Fast path: RETR_LIST without hierarchy → findTRUContours (parallel contour extraction)
if (mode == RETR_LIST && !_hierarchy.needed())
if (mode == RETR_LIST && !_hierarchy.needed() && _image.type() == CV_8UC1)
{
// findTRUContours requires FOREGROUND=255; binarize=true thresholds the padded
// image in-place, avoiding an extra allocation (findContours accepts any non-zero value)
+1 -1
View File
@@ -618,7 +618,7 @@ void findTRUContours(InputArray _src, OutputArrayOfArrays _contours, int minSize
{
CV_INSTRUMENT_REGION();
Mat src = _src.getMat();
CV_Assert(!src.empty() && src.type() == CV_8UC1);
CV_Assert(src.type() == CV_8UC1);
// Buffer handling
cv::Mat padded;
+46 -15
View File
@@ -415,22 +415,21 @@ public:
int w = std::min(tileSize, dst.cols - dst_x);
int h = std::min(tileSize, dst.rows - dst_y);
int src_x1 = dst_x - dx1, src_y1 = dst_y - dy1;
int src_x2 = dst_x + w + dx2, src_y2 = dst_y + h + dy2;
Size wholeSize;
Point ofs;
src.locateROI(wholeSize, ofs);
// Parent coordinates.
int src_x1 = ofs.x + dst_x - dx1, src_y1 = ofs.y + dst_y - dy1;
int src_x2 = ofs.x + dst_x + w + dx2,
src_y2 = ofs.y + dst_y + h + dy2;
int pad_top = std::max(0, -src_y1);
int pad_bottom = std::max(0, src_y2 - src.rows);
int pad_bottom = std::max(0, src_y2 - wholeSize.height);
int pad_left = std::max(0, -src_x1);
int pad_right = std::max(0, src_x2 - src.cols);
int pad_right = std::max(0, src_x2 - wholeSize.width);
int clamped_x1 = std::max(0, src_x1);
int clamped_y1 = std::max(0, src_y1);
int clamped_x2 = std::min(src.cols, src_x2);
int clamped_y2 = std::min(src.rows, src_y2);
Mat src_region = src(Rect(clamped_x1, clamped_y1,
clamped_x2 - clamped_x1,
clamped_y2 - clamped_y1));
Mat src_region = src(Rect(dst_x, dst_y, w, h)).adjustROI(dy1, dy2, dx1, dx2);
Mat tile_mat;
if (pad_top == 0 && pad_bottom == 0 && pad_left == 0 && pad_right == 0)
@@ -542,9 +541,41 @@ void FilterEngine__apply(FilterEngine& this_, const Mat& src, Mat& dst, const Si
(size_t)src.total() >= std::max((size_t)1024 * 1024, (size_t)nthreads * 64 * 1024) &&
this_.rowBorderType == this_.columnBorderType)
{
// For in-place operations (e.g. morphologyEx MORPH_OPEN), clone src so that
// concurrent tiles read from an immutable snapshot rather than racing on writes.
Mat src_copy = (src.data == dst.data) ? src.clone() : src;
// Robust cloning for in-place/overlapping operations with ROI support.
Size resolved_wsz = wsz;
Point resolved_ofs = ofs;
if (resolved_wsz.width < 0) {
src.locateROI(resolved_wsz, resolved_ofs);
}
bool overlap = (src.data <= dst.dataend && dst.data <= src.dataend);
Mat src_copy;
if (resolved_wsz == src.size()) {
src_copy = overlap ? src.clone() : src;
} else {
// In case of ROI.
Mat parent(resolved_wsz, src.type(),
(void*)(src.data - resolved_ofs.y * src.step -
resolved_ofs.x * src.elemSize()),
src.step);
if (overlap) {
int dx1 = this_.anchor.x, dx2 = this_.ksize.width - dx1 - 1;
int dy1 = this_.anchor.y, dy2 = this_.ksize.height - dy1 - 1;
int p_x1 = std::max(0, resolved_ofs.x - dx1);
int p_y1 = std::max(0, resolved_ofs.y - dy1);
// Clone the required region only.
Mat required_region = parent(Rect(resolved_ofs, src.size())).adjustROI(dy1, dy2, dx1, dx2).clone();
src_copy = required_region(Rect(resolved_ofs - Point(p_x1, p_y1), src.size()));
} else {
// Actually src_copy = src but makes sure src_copy is seen as a sub-matrix
// because sepFilter2D creates a submatrix on the fly without having it be
// an official sub-matrix (which would make locateROI fail in TiledFilterInvoker)
src_copy = parent(Rect(resolved_ofs, src.size()));
}
}
// Heuristic: Balance L2 cache locality (128) vs parallel load balancing (64).
int tileSize = (src.total() < (size_t)nthreads * 128 * 128 * 4) ? 64 : 128;
+24
View File
@@ -1409,6 +1409,30 @@ inline int hal_ni_laplacian(const uchar* src_data, size_t src_step, uchar* dst_d
#define cv_hal_laplacian hal_ni_laplacian
//! @endcond
/**
@brief Compute spatial gradient (Sobel X and Y simultaneously).
@param src_data Source image data (8-bit single channel)
@param src_step Source image step
@param dx_data Destination X-gradient data (16-bit signed)
@param dx_step Destination X-gradient step
@param dy_data Destination Y-gradient data (16-bit signed)
@param dy_step Destination Y-gradient step
@param width Image width
@param height Image height
@param ksize Kernel size (must be 3)
@param border_type Border type (BORDER_DEFAULT or BORDER_REPLICATE)
*/
inline int hal_ni_spatialGradient(const uchar* src_data, size_t src_step,
short* dx_data, size_t dx_step,
short* dy_data, size_t dy_step,
int width, int height,
int ksize, int border_type)
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_spatialGradient hal_ni_spatialGradient
//! @endcond
/**
@brief Perform Gaussian Blur and downsampling for input tile.
@param depth Depths of source and destination image
+7
View File
@@ -113,6 +113,13 @@ void spatialGradient( InputArray _src, OutputArray _dx, OutputArray _dy,
// TODO: Allow for other kernel sizes
CV_Assert(ksize == 3);
CALL_HAL(spatialGradient, cv_hal_spatialGradient,
src.data, src.step,
dx.ptr<short>(), dx.step,
dy.ptr<short>(), dy.step,
src.cols, src.rows,
ksize, borderType);
// Get dimensions
const int H = src.rows,
W = src.cols;
+57
View File
@@ -1450,4 +1450,61 @@ TEST(Imgproc_Filter2D, padding_bounds_roi_isolated)
}
}
class FastFilterEngineTest : public ::testing::Test {
protected:
void SetUp() override {
// Prepare separable kernels (3x3 averaging filter [1, 1, 1]).
kX = cv::Mat::ones(1, 3, CV_32F) / 3.0f;
kY = cv::Mat::ones(3, 1, CV_32F) / 3.0f;
}
cv::Mat kX, kY;
};
TEST_F(FastFilterEngineTest, Submatrix) {
// num_threads == 2 triggers the fast path.
for(int num_threads : {1, 2}) {
setNumThreads(num_threads);
Mat1b parent(1200, 1200, 255);
Mat roi = parent(Rect(100, 100, 1024, 1024));
roi.setTo(Scalar(0));
Mat dst;
sepFilter2D(roi, dst, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
// Before fix in fast path: dst.at<uchar>(0,0) == 0 (treated as isolated).
// With fix in fast path: dst.at<uchar>(0,0) > 0 (correctly reads 255 padding from parent).
EXPECT_GT(dst.at<uchar>(0, 0), 0);
// Filter in-place directly into 'roi' (dst == roi).
sepFilter2D(roi, roi, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
// Before fix in fast path: roi.at<uchar>(0,0) == 0 (cloned only ROI, lost parent padding).
// With fix in fast path: roi.at<uchar>(0,0) > 0 (clones required_region including padding).
EXPECT_GT(roi.at<uchar>(0, 0), 0);
}
}
TEST_F(FastFilterEngineTest, FullImage) {
// num_threads == 2 triggers the fast path.
for(int num_threads : {1, 2}) {
setNumThreads(num_threads);
Mat1b img(1024, 1024, 100);
Mat dst;
sepFilter2D(img, dst, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
// Verifies direct pass-through (src_copy = src) executes correctly.
EXPECT_EQ(dst.at<uchar>(0, 0), 100);
// Filter in-place directly into 'img' (dst == img).
sepFilter2D(img, img, -1, kX, kY, Point(-1, -1), 0, BORDER_REPLICATE);
// Verifies that full-image cloning (src.clone()) executes correctly without memory corruption.
EXPECT_EQ(img.at<uchar>(0, 0), 100);
}
}
}} // namespace
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python
'''
ECC multiscale alignment test
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
import inspect
import math
from tests_common import NewOpenCVTests
class eccms_test(NewOpenCVTests):
def test_eccms(self):
expected_res = np.array([
[1.0225, 0.0606, -28.6452],
[-0.0475, 1.0314, 11.819],
[8.21e-06, -3.65e-07, 1.0]
], dtype=np.float32)
largeGray0 = self.get_sample('cv/shared/halmosh0.jpg', cv.IMREAD_GRAYSCALE)
largeGray1 = self.get_sample('cv/shared/halmosh2.jpg', cv.IMREAD_GRAYSCALE)
roiMask0 = self.get_sample('cv/shared/halmosh0mask.png', cv.IMREAD_GRAYSCALE)
roiMask1 = self.get_sample('cv/shared/halmosh2mask.png', cv.IMREAD_GRAYSCALE)
if largeGray0 is None or largeGray1 is None or roiMask0 is None or roiMask1 is None:
self.assertEqual(0, 1, 'Missing test data')
found = np.eye(3, 3, dtype=np.float32)
n_iters = 23
termination_eps = 1e-6
params = cv.ECCParameters()
params.criteria = (cv.TERM_CRITERIA_COUNT + cv.TERM_CRITERIA_EPS, n_iters, termination_eps)
params.motionType = cv.MOTION_HOMOGRAPHY
params.nlevels = 5
params.itersPerLevel = [5, 10, 300, 300, 1000]
_, found = cv.findTransformECCMultiScale(largeGray0,largeGray1, found, params, roiMask0, roiMask1)
self.assertLess(cv.norm(found - expected_res, cv.NORM_L1), 0.1)
if __name__ == '__main__':
NewOpenCVTests.bootstrap()
@@ -453,10 +453,10 @@ Affects accuracy, especially when motionType == MOTION_TRANSLATION. (DEFAULT: IN
*/
struct CV_EXPORTS_W_SIMPLE ECCParameters
{
CV_WRAP ECCParameters() {}
CV_WRAP ECCParameters();
CV_PROP_RW int motionType = MOTION_AFFINE;
CV_PROP_RW cv::TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 50, 1e-6);
CV_PROP_RW std::vector<int> itersPerLevel = std::vector<int>();
CV_PROP_RW cv::TermCriteria criteria;
CV_PROP_RW std::vector<int> itersPerLevel;
CV_PROP_RW int gaussFiltSize = 5;
CV_PROP_RW int nlevels = 4;
CV_PROP_RW int interpolation = INTER_LINEAR;
+3
View File
@@ -9,6 +9,9 @@
\****************************************************************************************/
namespace cv {
ECCParameters::ECCParameters() : criteria(TermCriteria::COUNT + TermCriteria::EPS, 50, 1e-6)
{}
typedef std::vector<cv::Mat> MatPyramid;
template<int motionType> struct MotionTraits {};
+157
View File
@@ -0,0 +1,157 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
namespace opencv_test { namespace {
typedef testing::TestWithParam<tuple<Size, int, int> > Video_Acc_Cn4;
TEST_P(Video_Acc_Cn4, accuracy)
{
const Size size = get<0>(GetParam());
const int pattern = get<1>(GetParam());
const int srcType = get<2>(GetParam());
RNG& rng = theRNG();
Mat src(size, srcType);
Mat dst(size, CV_32FC4);
Mat mask(size, CV_8UC1);
if (srcType == CV_8UC4)
rng.fill(src, RNG::UNIFORM, Scalar::all(0), Scalar::all(256));
else
rng.fill(src, RNG::UNIFORM, Scalar::all(-10.0), Scalar::all(10.0));
rng.fill(dst, RNG::UNIFORM, Scalar::all(-1000.0), Scalar::all(1000.0));
for (int y = 0; y < mask.rows; ++y)
{
uchar* row = mask.ptr<uchar>(y);
for (int x = 0; x < mask.cols; ++x)
{
switch (pattern)
{
case 0:
row[x] = 0;
break;
case 1:
row[x] = 255;
break;
case 2:
row[x] = ((x + y) % 2) ? 255 : 0;
break;
case 3:
row[x] = ((x * 13 + y * 7) % 5) ? 255 : 0;
break;
default:
row[x] = ((x * 17 + y * 11) % 3) ? 255 : 0;
break;
}
}
}
Mat dstRef = dst.clone();
if (srcType == CV_32FC4)
{
for (int y = 0; y < src.rows; ++y)
{
const Vec4f* srcRow = src.ptr<Vec4f>(y);
Vec4f* dstRefRow = dstRef.ptr<Vec4f>(y);
const uchar* maskRow = mask.ptr<uchar>(y);
for (int x = 0; x < src.cols; ++x)
{
if (maskRow[x])
{
for (int c = 0; c < 4; ++c)
dstRefRow[x][c] += srcRow[x][c];
}
}
}
}
else
{
CV_Assert(srcType == CV_8UC4);
for (int y = 0; y < src.rows; ++y)
{
const Vec4b* srcRow = src.ptr<Vec4b>(y);
Vec4f* dstRefRow = dstRef.ptr<Vec4f>(y);
const uchar* maskRow = mask.ptr<uchar>(y);
for (int x = 0; x < src.cols; ++x)
{
if (maskRow[x])
{
for (int c = 0; c < 4; ++c)
dstRefRow[x][c] += static_cast<float>(srcRow[x][c]);
}
}
}
}
cv::accumulate(src, dst, mask);
const double err = cv::norm(dst, dstRef, NORM_INF);
EXPECT_EQ(0.0, err)
<< "size=" << size
<< ", pattern=" << pattern
<< ", srcType=" << srcType;
}
INSTANTIATE_TEST_CASE_P(Accumulate,
Video_Acc_Cn4,
testing::Combine(
testing::Values(Size(1, 1),
Size(3, 5),
Size(17, 7),
Size(37, 19),
Size(128, 16),
Size(641, 37)),
testing::Values(0, 1, 2, 3, 4),
testing::Values(CV_32FC4, CV_8UC4)));
}} // namespace
+3 -1
View File
@@ -1633,7 +1633,9 @@ bool CvCapture_MSMF::configureAudioFrame()
chunkLengthOfBytes = bufferAudioData.size();
audioSamplePos += chunkLengthOfBytes/bytesPerSample;
}
CV_Check((double)chunkLengthOfBytes, chunkLengthOfBytes >= INT_MIN || chunkLengthOfBytes <= INT_MAX, "MSMF: The chunkLengthOfBytes is out of the allowed range");
if ((LONGLONG)bufferAudioData.size() < chunkLengthOfBytes)
chunkLengthOfBytes = (LONGLONG)bufferAudioData.size();
CV_Check((double)chunkLengthOfBytes, chunkLengthOfBytes >= INT_MIN && chunkLengthOfBytes <= INT_MAX, "MSMF: The chunkLengthOfBytes is out of the allowed range");
copy(bufferAudioData.begin(), bufferAudioData.begin() + (int)chunkLengthOfBytes, std::back_inserter(audioDataInUse));
bufferAudioData.erase(bufferAudioData.begin(), bufferAudioData.begin() + (int)chunkLengthOfBytes);
if (audioFrame.empty())