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:
@@ -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];
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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. */
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user