mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge branch 4.x
This commit is contained in:
Vendored
+2
@@ -24,10 +24,12 @@
|
||||
#include "hal_rvv_1p0/mean.hpp" // core
|
||||
#include "hal_rvv_1p0/norm.hpp" // core
|
||||
#include "hal_rvv_1p0/norm_diff.hpp" // core
|
||||
#include "hal_rvv_1p0/norm_hamming.hpp" // core
|
||||
#include "hal_rvv_1p0/convert_scale.hpp" // core
|
||||
#include "hal_rvv_1p0/minmax.hpp" // core
|
||||
#include "hal_rvv_1p0/atan.hpp" // core
|
||||
#include "hal_rvv_1p0/split.hpp" // core
|
||||
#include "hal_rvv_1p0/flip.hpp" // core
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
#include <riscv_vector.h>
|
||||
#include <opencv2/core/base.hpp>
|
||||
#include <opencv2/core/utility.hpp>
|
||||
|
||||
namespace cv { namespace cv_hal_rvv {
|
||||
|
||||
#undef cv_hal_flip
|
||||
#define cv_hal_flip cv::cv_hal_rvv::flip
|
||||
|
||||
struct FlipVlen256
|
||||
{
|
||||
using TableElemType = uchar;
|
||||
using TableType = vuint8m8_t;
|
||||
|
||||
static inline size_t setvlmax()
|
||||
{
|
||||
return __riscv_vsetvlmax_e8m8();
|
||||
}
|
||||
|
||||
static inline TableType vid(size_t vl)
|
||||
{
|
||||
return __riscv_vid_v_u8m8(vl);
|
||||
}
|
||||
|
||||
static inline TableType loadTable(const TableElemType* ptr, size_t vl)
|
||||
{
|
||||
return __riscv_vle8_v_u8m8(ptr, vl);
|
||||
}
|
||||
|
||||
static inline void gather(const uchar* src, TableType tab, uchar* dst, size_t vl)
|
||||
{
|
||||
auto v = __riscv_vle8_v_u8m8(src, vl);
|
||||
__riscv_vse8(dst, __riscv_vrgather(v, tab, vl), vl);
|
||||
}
|
||||
};
|
||||
|
||||
struct FlipVlen512
|
||||
{
|
||||
using TableElemType = uint16_t;
|
||||
using TableType = vuint16m8_t;
|
||||
|
||||
static inline size_t setvlmax()
|
||||
{
|
||||
return __riscv_vsetvlmax_e8m4();
|
||||
}
|
||||
|
||||
static inline TableType vid(size_t vl)
|
||||
{
|
||||
return __riscv_vid_v_u16m8(vl);
|
||||
}
|
||||
|
||||
static inline TableType loadTable(const TableElemType* ptr, size_t vl)
|
||||
{
|
||||
return __riscv_vle16_v_u16m8(ptr, vl);
|
||||
}
|
||||
|
||||
static inline void gather(const uchar* src, TableType tab, uchar* dst, size_t vl)
|
||||
{
|
||||
auto v = __riscv_vle8_v_u8m4(src, vl);
|
||||
__riscv_vse8(dst, __riscv_vrgatherei16(v, tab, vl), vl);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline void flipFillBuffer(cv::AutoBuffer<T>& _buf, size_t len, int esz)
|
||||
{
|
||||
T* buf = _buf.data();
|
||||
for (int i = (int)len - esz; i >= 0; i -= esz, buf += esz)
|
||||
for (int j = 0; j < esz; j++)
|
||||
buf[j] = (T)(i + j);
|
||||
}
|
||||
|
||||
inline void flipX(int esz,
|
||||
const uchar* src_data,
|
||||
size_t src_step,
|
||||
int src_width,
|
||||
int src_height,
|
||||
uchar* dst_data,
|
||||
size_t dst_step)
|
||||
{
|
||||
size_t w = (size_t)src_width * esz;
|
||||
auto src0 = src_data, src1 = src_data + src_step * (src_height - 1);
|
||||
auto dst0 = dst_data, dst1 = dst_data + dst_step * (src_height - 1);
|
||||
size_t vl;
|
||||
for (src_height -= 2; src_height >= 0;
|
||||
src_height -= 2, src0 += src_step, dst0 += dst_step, src1 -= src_step, dst1 -= dst_step)
|
||||
{
|
||||
for (size_t i = 0; i < w; i += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e8m8(w - i);
|
||||
__riscv_vse8(dst1 + i, __riscv_vle8_v_u8m8(src0 + i, vl), vl);
|
||||
__riscv_vse8(dst0 + i, __riscv_vle8_v_u8m8(src1 + i, vl), vl);
|
||||
}
|
||||
}
|
||||
if (src_height == -1)
|
||||
{
|
||||
for (size_t i = 0; i < w; i += (int)vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e8m8(w - i);
|
||||
__riscv_vse8(dst0 + i, __riscv_vle8_v_u8m8(src1 + i, vl), vl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FlipVlen>
|
||||
inline void flipY(int esz,
|
||||
const uchar* src_data,
|
||||
size_t src_step,
|
||||
int src_width,
|
||||
int src_height,
|
||||
uchar* dst_data,
|
||||
size_t dst_step)
|
||||
{
|
||||
size_t w = (size_t)src_width * esz;
|
||||
size_t vl = std::min(FlipVlen::setvlmax() / esz * esz, w);
|
||||
typename FlipVlen::TableType tab_v;
|
||||
if (esz == 1)
|
||||
tab_v = __riscv_vrsub(FlipVlen::vid(vl), vl - 1, vl);
|
||||
else
|
||||
{
|
||||
cv::AutoBuffer<typename FlipVlen::TableElemType> buf(vl);
|
||||
flipFillBuffer(buf, vl, esz);
|
||||
tab_v = FlipVlen::loadTable(buf.data(), vl);
|
||||
}
|
||||
if (vl == w)
|
||||
for (; src_height; src_height--, src_data += src_step, dst_data += dst_step)
|
||||
FlipVlen::gather(src_data, tab_v, dst_data, vl);
|
||||
else
|
||||
for (; src_height; src_height--, src_data += src_step, dst_data += dst_step)
|
||||
{
|
||||
auto src0 = src_data, src1 = src_data + w - vl;
|
||||
auto dst0 = dst_data, dst1 = dst_data + w - vl;
|
||||
for (; src0 < src1 + vl; src0 += vl, src1 -= vl, dst0 += vl, dst1 -= vl)
|
||||
{
|
||||
FlipVlen::gather(src0, tab_v, dst1, vl);
|
||||
FlipVlen::gather(src1, tab_v, dst0, vl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FlipVlen>
|
||||
inline void flipXY(int esz,
|
||||
const uchar* src_data,
|
||||
size_t src_step,
|
||||
int src_width,
|
||||
int src_height,
|
||||
uchar* dst_data,
|
||||
size_t dst_step)
|
||||
{
|
||||
size_t w = (size_t)src_width * esz;
|
||||
size_t vl = std::min(FlipVlen::setvlmax() / esz * esz, w);
|
||||
typename FlipVlen::TableType tab_v;
|
||||
if (esz == 1)
|
||||
tab_v = __riscv_vrsub(FlipVlen::vid(vl), vl - 1, vl);
|
||||
else
|
||||
{
|
||||
cv::AutoBuffer<typename FlipVlen::TableElemType> buf(vl);
|
||||
flipFillBuffer(buf, vl, esz);
|
||||
tab_v = FlipVlen::loadTable(buf.data(), vl);
|
||||
}
|
||||
auto src0 = src_data, src1 = src_data + src_step * (src_height - 1);
|
||||
auto dst0 = dst_data, dst1 = dst_data + dst_step * (src_height - 1);
|
||||
if (vl == w)
|
||||
{
|
||||
for (src_height -= 2; src_height >= 0;
|
||||
src_height -= 2,
|
||||
src0 += src_step,
|
||||
dst0 += dst_step,
|
||||
src1 -= src_step,
|
||||
dst1 -= dst_step)
|
||||
{
|
||||
FlipVlen::gather(src0, tab_v, dst1, vl);
|
||||
FlipVlen::gather(src1, tab_v, dst0, vl);
|
||||
}
|
||||
if (src_height == -1)
|
||||
{
|
||||
FlipVlen::gather(src1, tab_v, dst0, vl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (src_height -= 2; src_height >= 0;
|
||||
src_height -= 2,
|
||||
src0 += src_step,
|
||||
dst0 += dst_step,
|
||||
src1 -= src_step,
|
||||
dst1 -= dst_step)
|
||||
{
|
||||
for (size_t i = 0; 2 * i < w; i += vl)
|
||||
{
|
||||
FlipVlen::gather(src0 + i, tab_v, dst1 + w - i - vl, vl);
|
||||
FlipVlen::gather(src0 + w - i - vl, tab_v, dst1 + i, vl);
|
||||
FlipVlen::gather(src1 + i, tab_v, dst0 + w - i - vl, vl);
|
||||
FlipVlen::gather(src1 + w - i - vl, tab_v, dst0 + i, vl);
|
||||
}
|
||||
}
|
||||
if (src_height == -1)
|
||||
{
|
||||
for (size_t i = 0; 2 * i < w; i += vl)
|
||||
{
|
||||
FlipVlen::gather(src1 + i, tab_v, dst0 + w - i - vl, vl);
|
||||
FlipVlen::gather(src1 + w - i - vl, tab_v, dst0 + i, vl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int flip(int src_type,
|
||||
const uchar* src_data,
|
||||
size_t src_step,
|
||||
int src_width,
|
||||
int src_height,
|
||||
uchar* dst_data,
|
||||
size_t dst_step,
|
||||
int flip_mode)
|
||||
{
|
||||
if (src_width < 0 || src_height < 0 || src_data == dst_data)
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
int esz = CV_ELEM_SIZE(src_type);
|
||||
if (flip_mode == 0)
|
||||
{
|
||||
flipX(esz, src_data, src_step, src_width, src_height, dst_data, dst_step);
|
||||
}
|
||||
else if (flip_mode > 0)
|
||||
{
|
||||
if (__riscv_vlenb() * 8 <= 256)
|
||||
flipY<FlipVlen256>(esz, src_data, src_step, src_width, src_height, dst_data, dst_step);
|
||||
else
|
||||
flipY<FlipVlen512>(esz, src_data, src_step, src_width, src_height, dst_data, dst_step);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (__riscv_vlenb() * 8 <= 256)
|
||||
flipXY<FlipVlen256>(esz, src_data, src_step, src_width, src_height, dst_data, dst_step);
|
||||
else
|
||||
flipXY<FlipVlen512>(esz, src_data, src_step, src_width, src_height, dst_data, dst_step);
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
}} // namespace cv::cv_hal_rvv
|
||||
+138
-179
@@ -17,236 +17,195 @@ namespace cv { namespace cv_hal_rvv {
|
||||
#undef cv_hal_merge64s
|
||||
#define cv_hal_merge64s cv::cv_hal_rvv::merge64s
|
||||
|
||||
#if defined __GNUC__
|
||||
__attribute__((optimize("no-tree-vectorize")))
|
||||
#endif
|
||||
#if defined __clang__ && __clang_major__ < 18
|
||||
#define OPENCV_HAL_IMPL_RVV_VCREATE_x2(suffix, width, v0, v1) \
|
||||
__riscv_vset_v_##suffix##m##width##_##suffix##m##width##x2(seg, 0, v0); \
|
||||
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x2(seg, 1, v1);
|
||||
|
||||
#define OPENCV_HAL_IMPL_RVV_VCREATE_x3(suffix, width, v0, v1, v2) \
|
||||
__riscv_vset_v_##suffix##m##width##_##suffix##m##width##x3(seg, 0, v0); \
|
||||
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x3(seg, 1, v1); \
|
||||
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x3(seg, 2, v2);
|
||||
|
||||
#define OPENCV_HAL_IMPL_RVV_VCREATE_x4(suffix, width, v0, v1, v2, v3) \
|
||||
__riscv_vset_v_##suffix##m##width##_##suffix##m##width##x4(seg, 0, v0); \
|
||||
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x4(seg, 1, v1); \
|
||||
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x4(seg, 2, v2); \
|
||||
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x4(seg, 3, v3);
|
||||
|
||||
#define __riscv_vcreate_v_u8m4x2(v0, v1) OPENCV_HAL_IMPL_RVV_VCREATE_x2(u8, 4, v0, v1)
|
||||
#define __riscv_vcreate_v_u8m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u8, 2, v0, v1, v2)
|
||||
#define __riscv_vcreate_v_u8m2x4(v0, v1, v2, v3) OPENCV_HAL_IMPL_RVV_VCREATE_x4(u8, 2, v0, v1, v2, v3)
|
||||
#define __riscv_vcreate_v_u16m4x2(v0, v1) OPENCV_HAL_IMPL_RVV_VCREATE_x2(u16, 4, v0, v1)
|
||||
#define __riscv_vcreate_v_u16m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u16, 2, v0, v1, v2)
|
||||
#define __riscv_vcreate_v_u16m2x4(v0, v1, v2, v3) OPENCV_HAL_IMPL_RVV_VCREATE_x4(u16, 2, v0, v1, v2, v3)
|
||||
#endif // clang < 18
|
||||
|
||||
inline int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
|
||||
int k = cn % 4 ? cn % 4 : 4;
|
||||
int i = 0;
|
||||
int vl = __riscv_vsetvlmax_e8m1();
|
||||
if( k == 1 )
|
||||
int vl = 0;
|
||||
if (cn == 1)
|
||||
{
|
||||
const uchar* src0 = src[0];
|
||||
for( ; i <= len - vl; i += vl)
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle8_v_u8m1(src0 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*cn, a, vl);
|
||||
vl = __riscv_vsetvl_e8m8(len - i);
|
||||
__riscv_vse8_v_u8m8(dst + i, __riscv_vle8_v_u8m8(src0 + i, vl), vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++)
|
||||
dst[i*cn] = src0[i];
|
||||
}
|
||||
else if( k == 2 )
|
||||
else if (cn == 2)
|
||||
{
|
||||
const uchar *src0 = src[0], *src1 = src[1];
|
||||
for( ; i <= len - vl; i += vl)
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle8_v_u8m1(src0 + i, vl);
|
||||
auto b = __riscv_vle8_v_u8m1(src1 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*cn, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 1, sizeof(uchar)*cn, b, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++ )
|
||||
{
|
||||
dst[i*cn] = src0[i];
|
||||
dst[i*cn+1] = src1[i];
|
||||
vl = __riscv_vsetvl_e8m4(len - i);
|
||||
vuint8m4x2_t seg = __riscv_vcreate_v_u8m4x2(
|
||||
__riscv_vle8_v_u8m4(src0 + i, vl),
|
||||
__riscv_vle8_v_u8m4(src1 + i, vl)
|
||||
);
|
||||
__riscv_vsseg2e8_v_u8m4x2(dst + i * cn, seg, vl);
|
||||
}
|
||||
}
|
||||
else if( k == 3 )
|
||||
else if (cn == 3)
|
||||
{
|
||||
const uchar *src0 = src[0], *src1 = src[1], *src2 = src[2];
|
||||
for( ; i <= len - vl; i += vl)
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle8_v_u8m1(src0 + i, vl);
|
||||
auto b = __riscv_vle8_v_u8m1(src1 + i, vl);
|
||||
auto c = __riscv_vle8_v_u8m1(src2 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*cn, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 1, sizeof(uchar)*cn, b, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 2, sizeof(uchar)*cn, c, vl);
|
||||
vl = __riscv_vsetvl_e8m2(len - i);
|
||||
vuint8m2x3_t seg = __riscv_vcreate_v_u8m2x3(
|
||||
__riscv_vle8_v_u8m2(src0 + i, vl),
|
||||
__riscv_vle8_v_u8m2(src1 + i, vl),
|
||||
__riscv_vle8_v_u8m2(src2 + i, vl)
|
||||
);
|
||||
__riscv_vsseg3e8_v_u8m2x3(dst + i * cn, seg, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++ )
|
||||
}
|
||||
else if (cn == 4)
|
||||
{
|
||||
const uchar *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
dst[i*cn] = src0[i];
|
||||
dst[i*cn+1] = src1[i];
|
||||
dst[i*cn+2] = src2[i];
|
||||
vl = __riscv_vsetvl_e8m2(len - i);
|
||||
vuint8m2x4_t seg = __riscv_vcreate_v_u8m2x4(
|
||||
__riscv_vle8_v_u8m2(src0 + i, vl),
|
||||
__riscv_vle8_v_u8m2(src1 + i, vl),
|
||||
__riscv_vle8_v_u8m2(src2 + i, vl),
|
||||
__riscv_vle8_v_u8m2(src3 + i, vl)
|
||||
);
|
||||
__riscv_vsseg4e8_v_u8m2x4(dst + i * cn, seg, vl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uchar *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
|
||||
for( ; i <= len - vl; i += vl)
|
||||
int k = 0;
|
||||
for (; k <= cn - 4; k += 4)
|
||||
{
|
||||
auto a = __riscv_vle8_v_u8m1(src0 + i, vl);
|
||||
auto b = __riscv_vle8_v_u8m1(src1 + i, vl);
|
||||
auto c = __riscv_vle8_v_u8m1(src2 + i, vl);
|
||||
auto d = __riscv_vle8_v_u8m1(src3 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn, sizeof(uchar)*cn, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 1, sizeof(uchar)*cn, b, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 2, sizeof(uchar)*cn, c, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + i*cn + 3, sizeof(uchar)*cn, d, vl);
|
||||
const uchar *src0 = src[k], *src1 = src[k + 1], *src2 = src[k + 2], *src3 = src[k + 3];
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e8m2(len - i);
|
||||
vuint8m2x4_t seg = __riscv_vcreate_v_u8m2x4(
|
||||
__riscv_vle8_v_u8m2(src0 + i, vl),
|
||||
__riscv_vle8_v_u8m2(src1 + i, vl),
|
||||
__riscv_vle8_v_u8m2(src2 + i, vl),
|
||||
__riscv_vle8_v_u8m2(src3 + i, vl)
|
||||
);
|
||||
__riscv_vssseg4e8_v_u8m2x4(dst + k + i * cn, cn, seg, vl);
|
||||
}
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++ )
|
||||
for (; k < cn; ++k)
|
||||
{
|
||||
dst[i*cn] = src0[i];
|
||||
dst[i*cn+1] = src1[i];
|
||||
dst[i*cn+2] = src2[i];
|
||||
dst[i*cn+3] = src3[i];
|
||||
}
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; k < cn; k += 4 )
|
||||
{
|
||||
const uchar *src0 = src[k], *src1 = src[k+1], *src2 = src[k+2], *src3 = src[k+3];
|
||||
i = 0;
|
||||
for( ; i <= len - vl; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle8_v_u8m1(src0 + i, vl);
|
||||
auto b = __riscv_vle8_v_u8m1(src1 + i, vl);
|
||||
auto c = __riscv_vle8_v_u8m1(src2 + i, vl);
|
||||
auto d = __riscv_vle8_v_u8m1(src3 + i, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + k+i*cn, sizeof(uchar)*cn, a, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + k+i*cn + 1, sizeof(uchar)*cn, b, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + k+i*cn + 2, sizeof(uchar)*cn, c, vl);
|
||||
__riscv_vsse8_v_u8m1(dst + k+i*cn + 3, sizeof(uchar)*cn, d, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++ )
|
||||
{
|
||||
dst[k+i*cn] = src0[i];
|
||||
dst[k+i*cn+1] = src1[i];
|
||||
dst[k+i*cn+2] = src2[i];
|
||||
dst[k+i*cn+3] = src3[i];
|
||||
const uchar* srcK = src[k];
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e8m2(len - i);
|
||||
vuint8m2_t seg = __riscv_vle8_v_u8m2(srcK + i, vl);
|
||||
__riscv_vsse8_v_u8m2(dst + k + i * cn, cn, seg, vl);
|
||||
}
|
||||
}
|
||||
}
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
#if defined __GNUC__
|
||||
__attribute__((optimize("no-tree-vectorize")))
|
||||
#endif
|
||||
inline int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
|
||||
int k = cn % 4 ? cn % 4 : 4;
|
||||
int i = 0;
|
||||
int vl = __riscv_vsetvlmax_e16m1();
|
||||
if( k == 1 )
|
||||
int vl = 0;
|
||||
if (cn == 1)
|
||||
{
|
||||
const ushort* src0 = src[0];
|
||||
for( ; i <= len - vl; i += vl)
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle16_v_u16m1(src0 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*cn, a, vl);
|
||||
vl = __riscv_vsetvl_e16m8(len - i);
|
||||
__riscv_vse16_v_u16m8(dst + i, __riscv_vle16_v_u16m8(src0 + i, vl), vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++)
|
||||
dst[i*cn] = src0[i];
|
||||
}
|
||||
else if( k == 2 )
|
||||
else if (cn == 2)
|
||||
{
|
||||
const ushort *src0 = src[0], *src1 = src[1];
|
||||
for( ; i <= len - vl; i += vl)
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle16_v_u16m1(src0 + i, vl);
|
||||
auto b = __riscv_vle16_v_u16m1(src1 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*cn, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 1, sizeof(ushort)*cn, b, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++ )
|
||||
{
|
||||
dst[i*cn] = src0[i];
|
||||
dst[i*cn+1] = src1[i];
|
||||
vl = __riscv_vsetvl_e16m4(len - i);
|
||||
vuint16m4x2_t seg = __riscv_vcreate_v_u16m4x2(
|
||||
__riscv_vle16_v_u16m4(src0 + i, vl),
|
||||
__riscv_vle16_v_u16m4(src1 + i, vl)
|
||||
);
|
||||
__riscv_vsseg2e16_v_u16m4x2(dst + i * cn, seg, vl);
|
||||
}
|
||||
}
|
||||
else if( k == 3 )
|
||||
else if (cn == 3)
|
||||
{
|
||||
const ushort *src0 = src[0], *src1 = src[1], *src2 = src[2];
|
||||
for( ; i <= len - vl; i += vl)
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle16_v_u16m1(src0 + i, vl);
|
||||
auto b = __riscv_vle16_v_u16m1(src1 + i, vl);
|
||||
auto c = __riscv_vle16_v_u16m1(src2 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*cn, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 1, sizeof(ushort)*cn, b, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 2, sizeof(ushort)*cn, c, vl);
|
||||
vl = __riscv_vsetvl_e16m2(len - i);
|
||||
vuint16m2x3_t seg = __riscv_vcreate_v_u16m2x3(
|
||||
__riscv_vle16_v_u16m2(src0 + i, vl),
|
||||
__riscv_vle16_v_u16m2(src1 + i, vl),
|
||||
__riscv_vle16_v_u16m2(src2 + i, vl)
|
||||
);
|
||||
__riscv_vsseg3e16_v_u16m2x3(dst + i * cn, seg, vl);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++ )
|
||||
}
|
||||
else if (cn == 4)
|
||||
{
|
||||
const ushort *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
dst[i*cn] = src0[i];
|
||||
dst[i*cn+1] = src1[i];
|
||||
dst[i*cn+2] = src2[i];
|
||||
vl = __riscv_vsetvl_e16m2(len - i);
|
||||
vuint16m2x4_t seg = __riscv_vcreate_v_u16m2x4(
|
||||
__riscv_vle16_v_u16m2(src0 + i, vl),
|
||||
__riscv_vle16_v_u16m2(src1 + i, vl),
|
||||
__riscv_vle16_v_u16m2(src2 + i, vl),
|
||||
__riscv_vle16_v_u16m2(src3 + i, vl)
|
||||
);
|
||||
__riscv_vsseg4e16_v_u16m2x4(dst + i * cn, seg, vl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const ushort *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
|
||||
for( ; i <= len - vl; i += vl)
|
||||
int k = 0;
|
||||
for (; k <= cn - 4; k += 4)
|
||||
{
|
||||
auto a = __riscv_vle16_v_u16m1(src0 + i, vl);
|
||||
auto b = __riscv_vle16_v_u16m1(src1 + i, vl);
|
||||
auto c = __riscv_vle16_v_u16m1(src2 + i, vl);
|
||||
auto d = __riscv_vle16_v_u16m1(src3 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn, sizeof(ushort)*cn, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 1, sizeof(ushort)*cn, b, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 2, sizeof(ushort)*cn, c, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + i*cn + 3, sizeof(ushort)*cn, d, vl);
|
||||
const ushort *src0 = src[k], *src1 = src[k + 1], *src2 = src[k + 2], *src3 = src[k + 3];
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e16m2(len - i);
|
||||
vuint16m2x4_t seg = __riscv_vcreate_v_u16m2x4(
|
||||
__riscv_vle16_v_u16m2(src0 + i, vl),
|
||||
__riscv_vle16_v_u16m2(src1 + i, vl),
|
||||
__riscv_vle16_v_u16m2(src2 + i, vl),
|
||||
__riscv_vle16_v_u16m2(src3 + i, vl)
|
||||
);
|
||||
__riscv_vssseg4e16_v_u16m2x4(dst + k + i * cn, cn * sizeof(ushort), seg, vl);
|
||||
}
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; i < len; i++ )
|
||||
for (; k < cn; ++k)
|
||||
{
|
||||
dst[i*cn] = src0[i];
|
||||
dst[i*cn+1] = src1[i];
|
||||
dst[i*cn+2] = src2[i];
|
||||
dst[i*cn+3] = src3[i];
|
||||
}
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for( ; k < cn; k += 4 )
|
||||
{
|
||||
const uint16_t *src0 = src[k], *src1 = src[k+1], *src2 = src[k+2], *src3 = src[k+3];
|
||||
i = 0;
|
||||
for( ; i <= len - vl; i += vl)
|
||||
{
|
||||
auto a = __riscv_vle16_v_u16m1(src0 + i, vl);
|
||||
auto b = __riscv_vle16_v_u16m1(src1 + i, vl);
|
||||
auto c = __riscv_vle16_v_u16m1(src2 + i, vl);
|
||||
auto d = __riscv_vle16_v_u16m1(src3 + i, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + k+i*cn, sizeof(ushort)*cn, a, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + k+i*cn + 1, sizeof(ushort)*cn, b, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + k+i*cn + 2, sizeof(ushort)*cn, c, vl);
|
||||
__riscv_vsse16_v_u16m1(dst + k+i*cn + 3, sizeof(ushort)*cn, d, vl);
|
||||
}
|
||||
for( ; i < len; i++ )
|
||||
{
|
||||
dst[k+i*cn] = src0[i];
|
||||
dst[k+i*cn+1] = src1[i];
|
||||
dst[k+i*cn+2] = src2[i];
|
||||
dst[k+i*cn+3] = src3[i];
|
||||
const ushort* srcK = src[k];
|
||||
for (int i = 0; i < len; i += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e16m2(len - i);
|
||||
vuint16m2_t seg = __riscv_vle16_v_u16m2(srcK + i, vl);
|
||||
__riscv_vsse16_v_u16m2(dst + k + i * cn, cn * sizeof(ushort), seg, vl);
|
||||
}
|
||||
}
|
||||
}
|
||||
return CV_HAL_ERROR_OK;
|
||||
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
#include <riscv_vector.h>
|
||||
#include <opencv2/core/base.hpp>
|
||||
|
||||
namespace cv { namespace cv_hal_rvv {
|
||||
|
||||
#undef cv_hal_normHamming8u
|
||||
#define cv_hal_normHamming8u cv::cv_hal_rvv::normHamming8u
|
||||
#undef cv_hal_normHammingDiff8u
|
||||
#define cv_hal_normHammingDiff8u cv::cv_hal_rvv::normHammingDiff8u
|
||||
|
||||
template <typename CellType>
|
||||
inline void normHammingCnt_m8(vuint8m8_t v, vbool1_t mask, size_t len_bool, size_t& result)
|
||||
{
|
||||
auto v_bool0 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 0));
|
||||
auto v_bool1 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 1));
|
||||
auto v_bool2 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 2));
|
||||
auto v_bool3 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 3));
|
||||
auto v_bool4 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 4));
|
||||
auto v_bool5 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 5));
|
||||
auto v_bool6 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 6));
|
||||
auto v_bool7 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 7));
|
||||
result += CellType::popcount(v_bool0, mask, len_bool);
|
||||
result += CellType::popcount(v_bool1, mask, len_bool);
|
||||
result += CellType::popcount(v_bool2, mask, len_bool);
|
||||
result += CellType::popcount(v_bool3, mask, len_bool);
|
||||
result += CellType::popcount(v_bool4, mask, len_bool);
|
||||
result += CellType::popcount(v_bool5, mask, len_bool);
|
||||
result += CellType::popcount(v_bool6, mask, len_bool);
|
||||
result += CellType::popcount(v_bool7, mask, len_bool);
|
||||
}
|
||||
|
||||
template <typename CellType>
|
||||
inline void normHammingCnt_m1(vuint8m1_t v, vbool1_t mask, size_t len_bool, size_t& result)
|
||||
{
|
||||
auto v_bool = __riscv_vreinterpret_b1(v);
|
||||
result += CellType::popcount(v_bool, mask, len_bool);
|
||||
}
|
||||
|
||||
struct NormHammingCell1
|
||||
{
|
||||
static inline vbool1_t generateMask([[maybe_unused]] size_t len)
|
||||
{
|
||||
return vbool1_t();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void preprocess([[maybe_unused]] T& v, [[maybe_unused]] size_t len)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline size_t popcount(T v, [[maybe_unused]] vbool1_t mask, size_t len_bool)
|
||||
{
|
||||
return __riscv_vcpop(v, len_bool);
|
||||
}
|
||||
};
|
||||
|
||||
struct NormHammingCell2
|
||||
{
|
||||
static inline vbool1_t generateMask(size_t len)
|
||||
{
|
||||
return __riscv_vreinterpret_b1(__riscv_vmv_v_x_u8m1(0x55, len));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void preprocess(T& v, size_t len)
|
||||
{
|
||||
v = __riscv_vor(v, __riscv_vsrl(v, 1, len), len);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline size_t popcount(T v, vbool1_t mask, size_t len_bool)
|
||||
{
|
||||
return __riscv_vcpop(mask, v, len_bool);
|
||||
}
|
||||
};
|
||||
|
||||
struct NormHammingCell4
|
||||
{
|
||||
static inline vbool1_t generateMask(size_t len)
|
||||
{
|
||||
return __riscv_vreinterpret_b1(__riscv_vmv_v_x_u8m1(0x11, len));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void preprocess(T& v, size_t len)
|
||||
{
|
||||
v = __riscv_vor(v, __riscv_vsrl(v, 2, len), len);
|
||||
v = __riscv_vor(v, __riscv_vsrl(v, 1, len), len);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline size_t popcount(T v, vbool1_t mask, size_t len_bool)
|
||||
{
|
||||
return __riscv_vcpop(mask, v, len_bool);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CellType>
|
||||
inline void normHamming8uLoop(const uchar* a, size_t n, size_t& result)
|
||||
{
|
||||
size_t len = __riscv_vsetvlmax_e8m8();
|
||||
size_t len_bool = len * 8;
|
||||
vbool1_t mask = CellType::generateMask(len);
|
||||
|
||||
for (; n >= len; n -= len, a += len)
|
||||
{
|
||||
auto v = __riscv_vle8_v_u8m8(a, len);
|
||||
CellType::preprocess(v, len);
|
||||
normHammingCnt_m8<CellType>(v, mask, len_bool, result);
|
||||
}
|
||||
for (; n > 0; n -= len, a += len)
|
||||
{
|
||||
len = __riscv_vsetvl_e8m1(n);
|
||||
auto v = __riscv_vle8_v_u8m1(a, len);
|
||||
CellType::preprocess(v, len);
|
||||
normHammingCnt_m1<CellType>(v, mask, len * 8, result);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CellType>
|
||||
inline void normHammingDiff8uLoop(const uchar* a, const uchar* b, size_t n, size_t& result)
|
||||
{
|
||||
size_t len = __riscv_vsetvlmax_e8m8();
|
||||
size_t len_bool = len * 8;
|
||||
vbool1_t mask = CellType::generateMask(len);
|
||||
|
||||
for (; n >= len; n -= len, a += len, b += len)
|
||||
{
|
||||
auto v_a = __riscv_vle8_v_u8m8(a, len);
|
||||
auto v_b = __riscv_vle8_v_u8m8(b, len);
|
||||
auto v = __riscv_vxor(v_a, v_b, len);
|
||||
CellType::preprocess(v, len);
|
||||
normHammingCnt_m8<CellType>(v, mask, len_bool, result);
|
||||
}
|
||||
for (; n > 0; n -= len, a += len, b += len)
|
||||
{
|
||||
len = __riscv_vsetvl_e8m1(n);
|
||||
auto v_a = __riscv_vle8_v_u8m1(a, len);
|
||||
auto v_b = __riscv_vle8_v_u8m1(b, len);
|
||||
auto v = __riscv_vxor(v_a, v_b, len);
|
||||
CellType::preprocess(v, len);
|
||||
normHammingCnt_m1<CellType>(v, mask, len * 8, result);
|
||||
}
|
||||
}
|
||||
|
||||
inline int normHamming8u(const uchar* a, int n, int cellSize, int* result)
|
||||
{
|
||||
size_t _result = 0;
|
||||
|
||||
switch (cellSize)
|
||||
{
|
||||
case 1: normHamming8uLoop<NormHammingCell1>(a, n, _result); break;
|
||||
case 2: normHamming8uLoop<NormHammingCell2>(a, n, _result); break;
|
||||
case 4: normHamming8uLoop<NormHammingCell4>(a, n, _result); break;
|
||||
default: return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
*result = static_cast<int>(_result);
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
inline int normHammingDiff8u(const uchar* a, const uchar* b, int n, int cellSize, int* result)
|
||||
{
|
||||
size_t _result = 0;
|
||||
|
||||
switch (cellSize)
|
||||
{
|
||||
case 1: normHammingDiff8uLoop<NormHammingCell1>(a, b, n, _result); break;
|
||||
case 2: normHammingDiff8uLoop<NormHammingCell2>(a, b, n, _result); break;
|
||||
case 4: normHammingDiff8uLoop<NormHammingCell4>(a, b, n, _result); break;
|
||||
default: return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
*result = static_cast<int>(_result);
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
}} // namespace cv::cv_hal_rvv
|
||||
Vendored
+133
-1
@@ -1,5 +1,137 @@
|
||||
# Changelog
|
||||
|
||||
## [v2.5.3](https://github.com/uclouvain/openjpeg/releases/v2.5.3) (2024-12-09)
|
||||
|
||||
[Full Changelog](https://github.com/uclouvain/openjpeg/compare/v2.5.2...v2.5.3)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Memory Leak When Using Invalid Output Path in opj\_compress [\#1567](https://github.com/uclouvain/openjpeg/issues/1567)
|
||||
- heap-buffer-overflow at lib/openjp2/j2k.c:8460:84 in opj\_j2k\_add\_tlmarker in openjpeg/opj\_decompress [\#1564](https://github.com/uclouvain/openjpeg/issues/1564)
|
||||
- heap-buffer-overflow at bin/common/color.c:215:42 in sycc422\_to\_rgb in openjpeg/opj\_decompress [\#1563](https://github.com/uclouvain/openjpeg/issues/1563)
|
||||
- Can not open libjpeg [\#1550](https://github.com/uclouvain/openjpeg/issues/1550)
|
||||
- \[ERROR\] Wrong values for: w\(525\) h\(700\) numcomps\(0\) \(ihdr\) [\#1545](https://github.com/uclouvain/openjpeg/issues/1545)
|
||||
- Failed to Open a Specific JP2 file [\#1544](https://github.com/uclouvain/openjpeg/issues/1544)
|
||||
- Outdated File in OpenJPEG Project Leading to Vulnerability \(CVE-2016-9534\) [\#1539](https://github.com/uclouvain/openjpeg/issues/1539)
|
||||
- Heap-buffer-overflow in in opj\_mqc\_init\_dec\_common when disabling strict mode [\#1535](https://github.com/uclouvain/openjpeg/issues/1535)
|
||||
- Heap-buffer-overflow in in opj\_t1\_decode\_cblk when disabling strict mode [\#1533](https://github.com/uclouvain/openjpeg/issues/1533)
|
||||
- opj\_decode\_tile\_data takes a long time to decode a very small file [\#1524](https://github.com/uclouvain/openjpeg/issues/1524)
|
||||
- Release v2.5.2 tag is outside of the repository [\#1521](https://github.com/uclouvain/openjpeg/issues/1521)
|
||||
- Website broken [\#1513](https://github.com/uclouvain/openjpeg/issues/1513)
|
||||
- Guard Bits In CINEMA2K Profile [\#1340](https://github.com/uclouvain/openjpeg/issues/1340)
|
||||
- Support for OSX on ARM \(M1\) [\#1289](https://github.com/uclouvain/openjpeg/issues/1289)
|
||||
- Building on Windows creates \_\_stdcall-convention static lib/dll regardless of compiler settings [\#722](https://github.com/uclouvain/openjpeg/issues/722)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- sycc422\_to\_rgb\(\): fix out-of-bounds read accesses when 2 \* width\_component\_1\_or\_2 + 1 == with\_component\_0 [\#1566](https://github.com/uclouvain/openjpeg/pull/1566) ([rouault](https://github.com/rouault))
|
||||
- opj\_j2k\_add\_tlmarker\(\): validate that current tile-part number if smaller that total number of tile-parts [\#1565](https://github.com/uclouvain/openjpeg/pull/1565) ([rouault](https://github.com/rouault))
|
||||
- Amend fix of PR 1530 regarding m\_sot\_length check [\#1561](https://github.com/uclouvain/openjpeg/pull/1561) ([rouault](https://github.com/rouault))
|
||||
- Do not turn on 'TPsot==TNsot detection fix' when TNsot==1, and [\#1560](https://github.com/uclouvain/openjpeg/pull/1560) ([rouault](https://github.com/rouault))
|
||||
- opj\_j2k\_setup\_encoder\(\): set numgbits = 1 for Cinema2K [\#1559](https://github.com/uclouvain/openjpeg/pull/1559) ([rouault](https://github.com/rouault))
|
||||
- bench\_dwt: Add assert for memory allocation failure [\#1555](https://github.com/uclouvain/openjpeg/pull/1555) ([hleft](https://github.com/hleft))
|
||||
- Add AVX2 and AVX512 optimization [\#1552](https://github.com/uclouvain/openjpeg/pull/1552) ([tszumski](https://github.com/tszumski))
|
||||
- Updated softprops/action-gh-release to v2 [\#1551](https://github.com/uclouvain/openjpeg/pull/1551) ([radarhere](https://github.com/radarhere))
|
||||
- Updated softprops/action-gh-release to v2 [\#1549](https://github.com/uclouvain/openjpeg/pull/1549) ([radarhere](https://github.com/radarhere))
|
||||
- fix: abi check [\#1548](https://github.com/uclouvain/openjpeg/pull/1548) ([mayeut](https://github.com/mayeut))
|
||||
- fix: when EPH markers are specified, they are required. [\#1547](https://github.com/uclouvain/openjpeg/pull/1547) ([mayeut](https://github.com/mayeut))
|
||||
- CI: add macOS arm64 [\#1546](https://github.com/uclouvain/openjpeg/pull/1546) ([mayeut](https://github.com/mayeut))
|
||||
- thirdparty/libz: update to zlib-1.3.1 [\#1542](https://github.com/uclouvain/openjpeg/pull/1542) ([rouault](https://github.com/rouault))
|
||||
- thirdparty/libpng: update to libpng-1.6.43 [\#1541](https://github.com/uclouvain/openjpeg/pull/1541) ([rouault](https://github.com/rouault))
|
||||
- thirdparty/libtiff: update to libtiff 4.6.0 [\#1540](https://github.com/uclouvain/openjpeg/pull/1540) ([rouault](https://github.com/rouault))
|
||||
- Use TLM \(Tile Length Marker\) segments to optimize decoding [\#1538](https://github.com/uclouvain/openjpeg/pull/1538) ([rouault](https://github.com/rouault))
|
||||
- Add new test for file with non-consecutive tilepart and TLM marker [\#1537](https://github.com/uclouvain/openjpeg/pull/1537) ([rouault](https://github.com/rouault))
|
||||
- Avoid heap-buffer-overflow read on corrupted image in non-strict mode [\#1536](https://github.com/uclouvain/openjpeg/pull/1536) ([rouault](https://github.com/rouault))
|
||||
- opj\_j2k\_read\_sod\(\): validate opj\_stream\_read\_data\(\) return to avoid … [\#1534](https://github.com/uclouvain/openjpeg/pull/1534) ([rouault](https://github.com/rouault))
|
||||
- Fixed typos [\#1532](https://github.com/uclouvain/openjpeg/pull/1532) ([radarhere](https://github.com/radarhere))
|
||||
- CI: pin macos job to macos-13 to get x86\_64 [\#1531](https://github.com/uclouvain/openjpeg/pull/1531) ([rouault](https://github.com/rouault))
|
||||
- Integer Overflow at j2k.c:9614 [\#1530](https://github.com/uclouvain/openjpeg/pull/1530) ([headshog](https://github.com/headshog))
|
||||
- Support setting enumcs for CMYK and EYCC color space [\#1529](https://github.com/uclouvain/openjpeg/pull/1529) ([radarhere](https://github.com/radarhere))
|
||||
- opj\_j2k\_decode\_tiles\(\): avoid use of uninitialized l\_current\_tile\_no variable [\#1528](https://github.com/uclouvain/openjpeg/pull/1528) ([rouault](https://github.com/rouault))
|
||||
- Updated actions/upload-artifact to v4 [\#1527](https://github.com/uclouvain/openjpeg/pull/1527) ([radarhere](https://github.com/radarhere))
|
||||
- Do not allow header length to be zero in non-zero length packet [\#1526](https://github.com/uclouvain/openjpeg/pull/1526) ([radarhere](https://github.com/radarhere))
|
||||
- Fix building on OpenBSD big endian hosts [\#1520](https://github.com/uclouvain/openjpeg/pull/1520) ([brad0](https://github.com/brad0))
|
||||
|
||||
## [v2.5.2](https://github.com/uclouvain/openjpeg/releases/v2.5.2) (2024-02-28)
|
||||
|
||||
[Full Changelog](https://github.com/uclouvain/openjpeg/compare/v2.5.1...v2.5.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- API breakage in 2.5.1 / openjpeg version no longer detected \(openjpeg.h no longer includes opj\_config.h\) [\#1514](https://github.com/uclouvain/openjpeg/issues/1514)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- openjpeg.h: make sure to include opj\_config.h \(fixes \#1514\) [\#1515](https://github.com/uclouvain/openjpeg/pull/1515) ([rouault](https://github.com/rouault))
|
||||
|
||||
## [v2.5.1](https://github.com/uclouvain/openjpeg/releases/v2.5.1) (2024-02-26)
|
||||
|
||||
[Full Changelog](https://github.com/uclouvain/openjpeg/compare/v2.5.0...v2.5.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Exist a undefined-behavior issue in file src/lib/openjp2/dwt.c:2124 [\#1505](https://github.com/uclouvain/openjpeg/issues/1505)
|
||||
- Potential double-free vulnerability in j2k.c [\#1498](https://github.com/uclouvain/openjpeg/issues/1498)
|
||||
- opj\_compress -I / -mct 0 should conflict each others [\#1485](https://github.com/uclouvain/openjpeg/issues/1485)
|
||||
- Exist a undefined-behavior issue in file src/lib/openjp2/tcd.c:2327 [\#1480](https://github.com/uclouvain/openjpeg/issues/1480)
|
||||
- OOM in opj\_decompress [\#1476](https://github.com/uclouvain/openjpeg/issues/1476)
|
||||
- v2.5.0 cannot be built successfully on aarch64 CentOS machine [\#1475](https://github.com/uclouvain/openjpeg/issues/1475)
|
||||
- \[ Heap Overflow \] opj\_decompress [\#1473](https://github.com/uclouvain/openjpeg/issues/1473)
|
||||
- Possible bug reading JP2 as grayscale when should be in color [\#1464](https://github.com/uclouvain/openjpeg/issues/1464)
|
||||
- Crashes due to internal bad memory references when using reduce on a truncated file. [\#1459](https://github.com/uclouvain/openjpeg/issues/1459)
|
||||
- No error.h \(non standard compliant\) [\#1453](https://github.com/uclouvain/openjpeg/issues/1453)
|
||||
- JP2 File incorrectly decompressed to noise [\#1447](https://github.com/uclouvain/openjpeg/issues/1447)
|
||||
- UB in tcd.c opj\_tcd\_dc\_level\_shift\_decode - pointer arithmetic on NULL pointer [\#1445](https://github.com/uclouvain/openjpeg/issues/1445)
|
||||
- UB in ht\_dec.c opj\_t1\_ht\_decode\_cblk - memcpy invoked on NULL pointer [\#1444](https://github.com/uclouvain/openjpeg/issues/1444)
|
||||
- Integer Overflow in `src/lib/openjp2/image.c` [\#1438](https://github.com/uclouvain/openjpeg/issues/1438)
|
||||
- Integer-overflow · opj\_t1\_encode\_cblk [\#1432](https://github.com/uclouvain/openjpeg/issues/1432)
|
||||
- OSX m1 v2.5.0 build fail [\#1430](https://github.com/uclouvain/openjpeg/issues/1430)
|
||||
- Pixel value could be changed by 0-4 after compression and decompression [\#1429](https://github.com/uclouvain/openjpeg/issues/1429)
|
||||
- Cannot determine library version at compile time [\#1428](https://github.com/uclouvain/openjpeg/issues/1428)
|
||||
- ARM builds on Windows unsupported with Version 2.5.0 [\#1422](https://github.com/uclouvain/openjpeg/issues/1422)
|
||||
- opj\_decompress heap overflow Denial of Service issue [\#1413](https://github.com/uclouvain/openjpeg/issues/1413)
|
||||
- Color channel swapping for some JPEG2000 pictures [\#1382](https://github.com/uclouvain/openjpeg/issues/1382)
|
||||
- Heap-buffer-overflow in color.c:379:42 in sycc420\_to\_rgb [\#1347](https://github.com/uclouvain/openjpeg/issues/1347)
|
||||
- No colorspace information after opj\_read\_header [\#570](https://github.com/uclouvain/openjpeg/issues/570)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- opj\_t2\_read\_packet\_header\(\): avoid unsigned integer overflow [\#1511](https://github.com/uclouvain/openjpeg/pull/1511) ([rouault](https://github.com/rouault))
|
||||
- opj\_dwt\_decode\_tile\(\): avoid potential UndefinedBehaviorSanitizer 'applying zero offset to null pointer' \(fixes \#1505\) [\#1510](https://github.com/uclouvain/openjpeg/pull/1510) ([rouault](https://github.com/rouault))
|
||||
- opj\_decompress: fix off-by-one read heap-buffer-overflow in sycc420\_to\_rgb\(\) when x0 and y0 are odd \(CVE-2021-3575, fixes \#1347\) [\#1509](https://github.com/uclouvain/openjpeg/pull/1509) ([rouault](https://github.com/rouault))
|
||||
- Always install pkgconfig files [\#1507](https://github.com/uclouvain/openjpeg/pull/1507) ([kmilos](https://github.com/kmilos))
|
||||
- CMake: drop support for cmake \< 3.5 [\#1503](https://github.com/uclouvain/openjpeg/pull/1503) ([domin144](https://github.com/domin144))
|
||||
- Fix compiler error on Windows [\#1502](https://github.com/uclouvain/openjpeg/pull/1502) ([scaramallion](https://github.com/scaramallion))
|
||||
- opj\_tcd\_dc\_level\_shift\_decode\(\): avoid increment nullptr \(fixes \#1480\) [\#1496](https://github.com/uclouvain/openjpeg/pull/1496) ([rouault](https://github.com/rouault))
|
||||
- Fix CI [\#1495](https://github.com/uclouvain/openjpeg/pull/1495) ([rouault](https://github.com/rouault))
|
||||
- suppress warning during build using clang [\#1494](https://github.com/uclouvain/openjpeg/pull/1494) ([tomoaki0705](https://github.com/tomoaki0705))
|
||||
- Add cmake version file [\#1493](https://github.com/uclouvain/openjpeg/pull/1493) ([domin144](https://github.com/domin144))
|
||||
- fix ht\_dec.c:1215 [\#1492](https://github.com/uclouvain/openjpeg/pull/1492) ([headshog](https://github.com/headshog))
|
||||
- Integer Overflow at j2k.c:11114 [\#1491](https://github.com/uclouvain/openjpeg/pull/1491) ([headshog](https://github.com/headshog))
|
||||
- Integer Overflow at j2k.c:3962 [\#1490](https://github.com/uclouvain/openjpeg/pull/1490) ([headshog](https://github.com/headshog))
|
||||
- Fixed typos [\#1486](https://github.com/uclouvain/openjpeg/pull/1486) ([radarhere](https://github.com/radarhere))
|
||||
- Require `stdint.h` & `inttypes.h` [\#1484](https://github.com/uclouvain/openjpeg/pull/1484) ([mayeut](https://github.com/mayeut))
|
||||
- fix: use `opj_uint_ceildiv` instead of `opj_int_ceildiv` when necessary [\#1482](https://github.com/uclouvain/openjpeg/pull/1482) ([mayeut](https://github.com/mayeut))
|
||||
- ht\_dec.c: Improve MSVC arm64 popcount performance [\#1479](https://github.com/uclouvain/openjpeg/pull/1479) ([PeterJohnson](https://github.com/PeterJohnson))
|
||||
- opj\_jp2\_read\_header\(\): move setting color\_space here instead in opj\_jp2\_decode\(\)/get\_tile\(\) \(fixes \#570\) [\#1463](https://github.com/uclouvain/openjpeg/pull/1463) ([rouault](https://github.com/rouault))
|
||||
- CMake: error out on warnings for strict/missing prototypes. [\#1462](https://github.com/uclouvain/openjpeg/pull/1462) ([sebras](https://github.com/sebras))
|
||||
- Fix CI [\#1461](https://github.com/uclouvain/openjpeg/pull/1461) ([rouault](https://github.com/rouault))
|
||||
- opj\_t2\_skip\_packet\_data\(\): avoid out-of-bounds reads on truncated images in non-strict mode \(fixes \#1459\) [\#1460](https://github.com/uclouvain/openjpeg/pull/1460) ([rouault](https://github.com/rouault))
|
||||
- Fix \#1424 [\#1456](https://github.com/uclouvain/openjpeg/pull/1456) ([autoantwort](https://github.com/autoantwort))
|
||||
- openjp2/j2k: replace sprintf calls with snprintf [\#1450](https://github.com/uclouvain/openjpeg/pull/1450) ([markmentovai](https://github.com/markmentovai))
|
||||
- Fix incorrect decoding of image with large number of progression levels [\#1448](https://github.com/uclouvain/openjpeg/pull/1448) ([rouault](https://github.com/rouault))
|
||||
- Fix Heap-buffer-overflow READ in opj\_jp2\_apply\_pclr [\#1441](https://github.com/uclouvain/openjpeg/pull/1441) ([sashashura](https://github.com/sashashura))
|
||||
- Significant speed-up rate allocation by rate/distoratio ratio [\#1440](https://github.com/uclouvain/openjpeg/pull/1440) ([rouault](https://github.com/rouault))
|
||||
- Make OpenJPEGConfig.cmake relocatable with CMake \> 3.0 [\#1439](https://github.com/uclouvain/openjpeg/pull/1439) ([arichardson](https://github.com/arichardson))
|
||||
- Replace the assert in mel\_init to an if statement to address an issue with fuzzing. [\#1436](https://github.com/uclouvain/openjpeg/pull/1436) ([aous72](https://github.com/aous72))
|
||||
- opj\_t1\_encode\_cblk\(\): avoid undefined behaviour on fuzzed input \(fixes \#1432\) [\#1433](https://github.com/uclouvain/openjpeg/pull/1433) ([rouault](https://github.com/rouault))
|
||||
- Build: fix linking of executables on some systems where TIFF/LCMS2 static libraries are not in system directories \(fixes \#1430\) [\#1431](https://github.com/uclouvain/openjpeg/pull/1431) ([rouault](https://github.com/rouault))
|
||||
- Fix opj\_t1\_allocate\_buffers malloc size error [\#1426](https://github.com/uclouvain/openjpeg/pull/1426) ([zodf0055980](https://github.com/zodf0055980))
|
||||
- Switch to GNUInstallDirs \[v2\] [\#1424](https://github.com/uclouvain/openjpeg/pull/1424) ([laumann](https://github.com/laumann))
|
||||
- Fix windows arm builds [\#1423](https://github.com/uclouvain/openjpeg/pull/1423) ([Neumann-A](https://github.com/Neumann-A))
|
||||
- pkgconfig: Define OPJ\_STATIC for static linking with pkgconf [\#1421](https://github.com/uclouvain/openjpeg/pull/1421) ([Biswa96](https://github.com/Biswa96))
|
||||
|
||||
|
||||
## [v2.5.0](https://github.com/uclouvain/openjpeg/releases/v2.5.0) (2022-05-13)
|
||||
|
||||
[Full Changelog](https://github.com/uclouvain/openjpeg/compare/v2.4.0...v2.5.0)
|
||||
@@ -217,7 +349,7 @@
|
||||
- LINUX install doesn't work when building shared libraries is disabled [\#1155](https://github.com/uclouvain/openjpeg/issues/1155)
|
||||
- OPENJPEG null ptr dereference in openjpeg-2.3.0/src/bin/jp2/convert.c:2243 [\#1152](https://github.com/uclouvain/openjpeg/issues/1152)
|
||||
- How to drop certain subbands/layers in DWT [\#1147](https://github.com/uclouvain/openjpeg/issues/1147)
|
||||
- where is the MQ-Coder ouput stream in t2.c? [\#1146](https://github.com/uclouvain/openjpeg/issues/1146)
|
||||
- where is the MQ-Coder output stream in t2.c? [\#1146](https://github.com/uclouvain/openjpeg/issues/1146)
|
||||
- OpenJPEG 2.3 \(and 2.2?\) multi component image fails to decode with KDU v7.10 [\#1132](https://github.com/uclouvain/openjpeg/issues/1132)
|
||||
- Missing checks for header\_info.height and header\_info.width in function pnmtoimage in src/bin/jpwl/convert.c, which can lead to heap buffer overflow [\#1126](https://github.com/uclouvain/openjpeg/issues/1126)
|
||||
- Assertion Failure in jp2.c [\#1125](https://github.com/uclouvain/openjpeg/issues/1125)
|
||||
|
||||
Vendored
+1
-1
@@ -23,7 +23,7 @@ ocv_warnings_disable(CMAKE_C_FLAGS
|
||||
# OPENJPEG version number, useful for packaging and doxygen doc:
|
||||
set(OPENJPEG_VERSION_MAJOR 2)
|
||||
set(OPENJPEG_VERSION_MINOR 5)
|
||||
set(OPENJPEG_VERSION_BUILD 0)
|
||||
set(OPENJPEG_VERSION_BUILD 3)
|
||||
set(OPENJPEG_VERSION
|
||||
"${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}")
|
||||
set(PACKAGE_VERSION
|
||||
|
||||
+1
@@ -64,6 +64,7 @@ void init_tilec(opj_tcd_tilecomp_t * l_tilec,
|
||||
nValues = (size_t)(l_tilec->x1 - l_tilec->x0) *
|
||||
(size_t)(l_tilec->y1 - l_tilec->y0);
|
||||
l_tilec->data = (OPJ_INT32*) opj_malloc(sizeof(OPJ_INT32) * nValues);
|
||||
assert(l_tilec->data != NULL);
|
||||
for (i = 0; i < nValues; i++) {
|
||||
OPJ_INT32 val = getValue((OPJ_UINT32)i);
|
||||
if (irreversible) {
|
||||
|
||||
Vendored
+217
-7
@@ -52,7 +52,7 @@
|
||||
#ifdef __SSSE3__
|
||||
#include <tmmintrin.h>
|
||||
#endif
|
||||
#ifdef __AVX2__
|
||||
#if (defined(__AVX2__) || defined(__AVX512F__))
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
@@ -66,7 +66,10 @@
|
||||
#define OPJ_WS(i) v->mem[(i)*2]
|
||||
#define OPJ_WD(i) v->mem[(1+(i)*2)]
|
||||
|
||||
#ifdef __AVX2__
|
||||
#if defined(__AVX512F__)
|
||||
/** Number of int32 values in a AVX512 register */
|
||||
#define VREG_INT_COUNT 16
|
||||
#elif defined(__AVX2__)
|
||||
/** Number of int32 values in a AVX2 register */
|
||||
#define VREG_INT_COUNT 8
|
||||
#else
|
||||
@@ -331,6 +334,51 @@ static void opj_dwt_decode_1(const opj_dwt_t *v)
|
||||
|
||||
#endif /* STANDARD_SLOW_VERSION */
|
||||
|
||||
#if defined(__AVX512F__)
|
||||
static int32_t loop_short_sse(int32_t len, const int32_t** lf_ptr,
|
||||
const int32_t** hf_ptr, int32_t** out_ptr,
|
||||
int32_t* prev_even)
|
||||
{
|
||||
int32_t next_even;
|
||||
__m128i odd, even_m1, unpack1, unpack2;
|
||||
const int32_t batch = (len - 2) / 8;
|
||||
const __m128i two = _mm_set1_epi32(2);
|
||||
|
||||
for (int32_t i = 0; i < batch; i++) {
|
||||
const __m128i lf_ = _mm_loadu_si128((__m128i*)(*lf_ptr + 1));
|
||||
const __m128i hf1_ = _mm_loadu_si128((__m128i*)(*hf_ptr));
|
||||
const __m128i hf2_ = _mm_loadu_si128((__m128i*)(*hf_ptr + 1));
|
||||
|
||||
__m128i even = _mm_add_epi32(hf1_, hf2_);
|
||||
even = _mm_add_epi32(even, two);
|
||||
even = _mm_srai_epi32(even, 2);
|
||||
even = _mm_sub_epi32(lf_, even);
|
||||
|
||||
next_even = _mm_extract_epi32(even, 3);
|
||||
even_m1 = _mm_bslli_si128(even, 4);
|
||||
even_m1 = _mm_insert_epi32(even_m1, *prev_even, 0);
|
||||
|
||||
//out[0] + out[2]
|
||||
odd = _mm_add_epi32(even_m1, even);
|
||||
odd = _mm_srai_epi32(odd, 1);
|
||||
odd = _mm_add_epi32(odd, hf1_);
|
||||
|
||||
unpack1 = _mm_unpacklo_epi32(even_m1, odd);
|
||||
unpack2 = _mm_unpackhi_epi32(even_m1, odd);
|
||||
|
||||
_mm_storeu_si128((__m128i*)(*out_ptr + 0), unpack1);
|
||||
_mm_storeu_si128((__m128i*)(*out_ptr + 4), unpack2);
|
||||
|
||||
*prev_even = next_even;
|
||||
|
||||
*out_ptr += 8;
|
||||
*lf_ptr += 4;
|
||||
*hf_ptr += 4;
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(STANDARD_SLOW_VERSION)
|
||||
static void opj_idwt53_h_cas0(OPJ_INT32* tmp,
|
||||
const OPJ_INT32 sn,
|
||||
@@ -363,6 +411,145 @@ static void opj_idwt53_h_cas0(OPJ_INT32* tmp,
|
||||
if (!(len & 1)) { /* if len is even */
|
||||
tmp[len - 1] = in_odd[(len - 1) / 2] + tmp[len - 2];
|
||||
}
|
||||
#else
|
||||
#if defined(__AVX512F__)
|
||||
OPJ_INT32* out_ptr = tmp;
|
||||
int32_t prev_even = in_even[0] - ((in_odd[0] + 1) >> 1);
|
||||
|
||||
const __m512i permutevar_mask = _mm512_setr_epi32(
|
||||
0x10, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0c, 0x0d, 0x0e);
|
||||
const __m512i store1_perm = _mm512_setr_epi64(0x00, 0x01, 0x08, 0x09, 0x02,
|
||||
0x03, 0x0a, 0x0b);
|
||||
const __m512i store2_perm = _mm512_setr_epi64(0x04, 0x05, 0x0c, 0x0d, 0x06,
|
||||
0x07, 0x0e, 0x0f);
|
||||
|
||||
const __m512i two = _mm512_set1_epi32(2);
|
||||
|
||||
int32_t simd_batch_512 = (len - 2) / 32;
|
||||
int32_t leftover;
|
||||
|
||||
for (i = 0; i < simd_batch_512; i++) {
|
||||
const __m512i lf_avx2 = _mm512_loadu_si512((__m512i*)(in_even + 1));
|
||||
const __m512i hf1_avx2 = _mm512_loadu_si512((__m512i*)(in_odd));
|
||||
const __m512i hf2_avx2 = _mm512_loadu_si512((__m512i*)(in_odd + 1));
|
||||
int32_t next_even;
|
||||
__m512i duplicate, even_m1, odd, unpack1, unpack2, store1, store2;
|
||||
|
||||
__m512i even = _mm512_add_epi32(hf1_avx2, hf2_avx2);
|
||||
even = _mm512_add_epi32(even, two);
|
||||
even = _mm512_srai_epi32(even, 2);
|
||||
even = _mm512_sub_epi32(lf_avx2, even);
|
||||
|
||||
next_even = _mm_extract_epi32(_mm512_extracti32x4_epi32(even, 3), 3);
|
||||
|
||||
duplicate = _mm512_set1_epi32(prev_even);
|
||||
even_m1 = _mm512_permutex2var_epi32(even, permutevar_mask, duplicate);
|
||||
|
||||
//out[0] + out[2]
|
||||
odd = _mm512_add_epi32(even_m1, even);
|
||||
odd = _mm512_srai_epi32(odd, 1);
|
||||
odd = _mm512_add_epi32(odd, hf1_avx2);
|
||||
|
||||
unpack1 = _mm512_unpacklo_epi32(even_m1, odd);
|
||||
unpack2 = _mm512_unpackhi_epi32(even_m1, odd);
|
||||
|
||||
store1 = _mm512_permutex2var_epi64(unpack1, store1_perm, unpack2);
|
||||
store2 = _mm512_permutex2var_epi64(unpack1, store2_perm, unpack2);
|
||||
|
||||
_mm512_storeu_si512(out_ptr, store1);
|
||||
_mm512_storeu_si512(out_ptr + 16, store2);
|
||||
|
||||
prev_even = next_even;
|
||||
|
||||
out_ptr += 32;
|
||||
in_even += 16;
|
||||
in_odd += 16;
|
||||
}
|
||||
|
||||
leftover = len - simd_batch_512 * 32;
|
||||
if (leftover > 8) {
|
||||
leftover -= 8 * loop_short_sse(leftover, &in_even, &in_odd, &out_ptr,
|
||||
&prev_even);
|
||||
}
|
||||
out_ptr[0] = prev_even;
|
||||
|
||||
for (j = 1; j < (leftover - 2); j += 2) {
|
||||
out_ptr[2] = in_even[1] - ((in_odd[0] + (in_odd[1]) + 2) >> 2);
|
||||
out_ptr[1] = in_odd[0] + ((out_ptr[0] + out_ptr[2]) >> 1);
|
||||
in_even++;
|
||||
in_odd++;
|
||||
out_ptr += 2;
|
||||
}
|
||||
|
||||
if (len & 1) {
|
||||
out_ptr[2] = in_even[1] - ((in_odd[0] + 1) >> 1);
|
||||
out_ptr[1] = in_odd[0] + ((out_ptr[0] + out_ptr[2]) >> 1);
|
||||
} else { //!(len & 1)
|
||||
out_ptr[1] = in_odd[0] + out_ptr[0];
|
||||
}
|
||||
#elif defined(__AVX2__)
|
||||
OPJ_INT32* out_ptr = tmp;
|
||||
int32_t prev_even = in_even[0] - ((in_odd[0] + 1) >> 1);
|
||||
|
||||
const __m256i reg_permutevar_mask_move_right = _mm256_setr_epi32(0x00, 0x00,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06);
|
||||
const __m256i two = _mm256_set1_epi32(2);
|
||||
|
||||
int32_t simd_batch = (len - 2) / 16;
|
||||
int32_t next_even;
|
||||
__m256i even_m1, odd, unpack1_avx2, unpack2_avx2;
|
||||
|
||||
for (i = 0; i < simd_batch; i++) {
|
||||
const __m256i lf_avx2 = _mm256_loadu_si256((__m256i*)(in_even + 1));
|
||||
const __m256i hf1_avx2 = _mm256_loadu_si256((__m256i*)(in_odd));
|
||||
const __m256i hf2_avx2 = _mm256_loadu_si256((__m256i*)(in_odd + 1));
|
||||
|
||||
__m256i even = _mm256_add_epi32(hf1_avx2, hf2_avx2);
|
||||
even = _mm256_add_epi32(even, two);
|
||||
even = _mm256_srai_epi32(even, 2);
|
||||
even = _mm256_sub_epi32(lf_avx2, even);
|
||||
|
||||
next_even = _mm_extract_epi32(_mm256_extracti128_si256(even, 1), 3);
|
||||
even_m1 = _mm256_permutevar8x32_epi32(even, reg_permutevar_mask_move_right);
|
||||
even_m1 = _mm256_blend_epi32(even_m1, _mm256_set1_epi32(prev_even), (1 << 0));
|
||||
|
||||
//out[0] + out[2]
|
||||
odd = _mm256_add_epi32(even_m1, even);
|
||||
odd = _mm256_srai_epi32(odd, 1);
|
||||
odd = _mm256_add_epi32(odd, hf1_avx2);
|
||||
|
||||
unpack1_avx2 = _mm256_unpacklo_epi32(even_m1, odd);
|
||||
unpack2_avx2 = _mm256_unpackhi_epi32(even_m1, odd);
|
||||
|
||||
_mm_storeu_si128((__m128i*)(out_ptr + 0), _mm256_castsi256_si128(unpack1_avx2));
|
||||
_mm_storeu_si128((__m128i*)(out_ptr + 4), _mm256_castsi256_si128(unpack2_avx2));
|
||||
_mm_storeu_si128((__m128i*)(out_ptr + 8), _mm256_extracti128_si256(unpack1_avx2,
|
||||
0x1));
|
||||
_mm_storeu_si128((__m128i*)(out_ptr + 12),
|
||||
_mm256_extracti128_si256(unpack2_avx2, 0x1));
|
||||
|
||||
prev_even = next_even;
|
||||
|
||||
out_ptr += 16;
|
||||
in_even += 8;
|
||||
in_odd += 8;
|
||||
}
|
||||
out_ptr[0] = prev_even;
|
||||
for (j = simd_batch * 16 + 1; j < (len - 2); j += 2) {
|
||||
out_ptr[2] = in_even[1] - ((in_odd[0] + in_odd[1] + 2) >> 2);
|
||||
out_ptr[1] = in_odd[0] + ((out_ptr[0] + out_ptr[2]) >> 1);
|
||||
in_even++;
|
||||
in_odd++;
|
||||
out_ptr += 2;
|
||||
}
|
||||
|
||||
if (len & 1) {
|
||||
out_ptr[2] = in_even[1] - ((in_odd[0] + 1) >> 1);
|
||||
out_ptr[1] = in_odd[0] + ((out_ptr[0] + out_ptr[2]) >> 1);
|
||||
} else { //!(len & 1)
|
||||
out_ptr[1] = in_odd[0] + out_ptr[0];
|
||||
}
|
||||
#else
|
||||
OPJ_INT32 d1c, d1n, s1n, s0c, s0n;
|
||||
|
||||
@@ -397,7 +584,8 @@ static void opj_idwt53_h_cas0(OPJ_INT32* tmp,
|
||||
} else {
|
||||
tmp[len - 1] = d1n + s0n;
|
||||
}
|
||||
#endif
|
||||
#endif /*(__AVX512F__ || __AVX2__)*/
|
||||
#endif /*TWO_PASS_VERSION*/
|
||||
memcpy(tiledp, tmp, (OPJ_UINT32)len * sizeof(OPJ_INT32));
|
||||
}
|
||||
|
||||
@@ -511,10 +699,20 @@ static void opj_idwt53_h(const opj_dwt_t *dwt,
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (defined(__SSE2__) || defined(__AVX2__)) && !defined(STANDARD_SLOW_VERSION)
|
||||
#if (defined(__SSE2__) || defined(__AVX2__) || defined(__AVX512F__)) && !defined(STANDARD_SLOW_VERSION)
|
||||
|
||||
/* Conveniency macros to improve the readability of the formulas */
|
||||
#if __AVX2__
|
||||
#if defined(__AVX512F__)
|
||||
#define VREG __m512i
|
||||
#define LOAD_CST(x) _mm512_set1_epi32(x)
|
||||
#define LOAD(x) _mm512_loadu_si512((const VREG*)(x))
|
||||
#define LOADU(x) _mm512_loadu_si512((const VREG*)(x))
|
||||
#define STORE(x,y) _mm512_storeu_si512((VREG*)(x),(y))
|
||||
#define STOREU(x,y) _mm512_storeu_si512((VREG*)(x),(y))
|
||||
#define ADD(x,y) _mm512_add_epi32((x),(y))
|
||||
#define SUB(x,y) _mm512_sub_epi32((x),(y))
|
||||
#define SAR(x,y) _mm512_srai_epi32((x),(y))
|
||||
#elif defined(__AVX2__)
|
||||
#define VREG __m256i
|
||||
#define LOAD_CST(x) _mm256_set1_epi32(x)
|
||||
#define LOAD(x) _mm256_load_si256((const VREG*)(x))
|
||||
@@ -576,7 +774,10 @@ static void opj_idwt53_v_cas0_mcols_SSE2_OR_AVX2(
|
||||
const VREG two = LOAD_CST(2);
|
||||
|
||||
assert(len > 1);
|
||||
#if __AVX2__
|
||||
#if defined(__AVX512F__)
|
||||
assert(PARALLEL_COLS_53 == 32);
|
||||
assert(VREG_INT_COUNT == 16);
|
||||
#elif defined(__AVX2__)
|
||||
assert(PARALLEL_COLS_53 == 16);
|
||||
assert(VREG_INT_COUNT == 8);
|
||||
#else
|
||||
@@ -584,10 +785,13 @@ static void opj_idwt53_v_cas0_mcols_SSE2_OR_AVX2(
|
||||
assert(VREG_INT_COUNT == 4);
|
||||
#endif
|
||||
|
||||
//For AVX512 code aligned load/store is set to it's unaligned equivalents
|
||||
#if !defined(__AVX512F__)
|
||||
/* Note: loads of input even/odd values must be done in a unaligned */
|
||||
/* fashion. But stores in tmp can be done with aligned store, since */
|
||||
/* the temporary buffer is properly aligned */
|
||||
assert((OPJ_SIZE_T)tmp % (sizeof(OPJ_INT32) * VREG_INT_COUNT) == 0);
|
||||
#endif
|
||||
|
||||
s1n_0 = LOADU(in_even + 0);
|
||||
s1n_1 = LOADU(in_even + VREG_INT_COUNT);
|
||||
@@ -678,7 +882,10 @@ static void opj_idwt53_v_cas1_mcols_SSE2_OR_AVX2(
|
||||
const OPJ_INT32* in_odd = &tiledp_col[0];
|
||||
|
||||
assert(len > 2);
|
||||
#if __AVX2__
|
||||
#if defined(__AVX512F__)
|
||||
assert(PARALLEL_COLS_53 == 32);
|
||||
assert(VREG_INT_COUNT == 16);
|
||||
#elif defined(__AVX2__)
|
||||
assert(PARALLEL_COLS_53 == 16);
|
||||
assert(VREG_INT_COUNT == 8);
|
||||
#else
|
||||
@@ -686,10 +893,13 @@ static void opj_idwt53_v_cas1_mcols_SSE2_OR_AVX2(
|
||||
assert(VREG_INT_COUNT == 4);
|
||||
#endif
|
||||
|
||||
//For AVX512 code aligned load/store is set to it's unaligned equivalents
|
||||
#if !defined(__AVX512F__)
|
||||
/* Note: loads of input even/odd values must be done in a unaligned */
|
||||
/* fashion. But stores in tmp can be done with aligned store, since */
|
||||
/* the temporary buffer is properly aligned */
|
||||
assert((OPJ_SIZE_T)tmp % (sizeof(OPJ_INT32) * VREG_INT_COUNT) == 0);
|
||||
#endif
|
||||
|
||||
s1_0 = LOADU(in_even + stride);
|
||||
/* in_odd[0] - ((in_even[0] + s1 + 2) >> 2); */
|
||||
|
||||
Vendored
+3
-3
@@ -901,7 +901,7 @@ typedef struct frwd_struct {
|
||||
* X controls this value.
|
||||
*
|
||||
* Unstuffing prevent sequences that are more than 0xFF7F from appearing
|
||||
* in the conpressed sequence. So whenever a value of 0xFF is coded, the
|
||||
* in the compressed sequence. So whenever a value of 0xFF is coded, the
|
||||
* MSB of the next byte is set 0 and must be ignored during decoding.
|
||||
*
|
||||
* Reading can go beyond the end of buffer by up to 3 bytes.
|
||||
@@ -1032,7 +1032,7 @@ OPJ_UINT32 frwd_fetch(frwd_struct_t *msp)
|
||||
//************************************************************************/
|
||||
/** @brief Allocates T1 buffers
|
||||
*
|
||||
* @param [in, out] t1 is codeblock cofficients storage
|
||||
* @param [in, out] t1 is codeblock coefficients storage
|
||||
* @param [in] w is codeblock width
|
||||
* @param [in] h is codeblock height
|
||||
*/
|
||||
@@ -1120,7 +1120,7 @@ OPJ_BOOL opj_t1_ht_decode_cblk(opj_t1_t *t1,
|
||||
/** @brief Decodes one codeblock, processing the cleanup, siginificance
|
||||
* propagation, and magnitude refinement pass
|
||||
*
|
||||
* @param [in, out] t1 is codeblock cofficients storage
|
||||
* @param [in, out] t1 is codeblock coefficients storage
|
||||
* @param [in] cblk is codeblock properties
|
||||
* @param [in] orient is the subband to which the codeblock belongs (not needed)
|
||||
* @param [in] roishift is region of interest shift
|
||||
|
||||
Vendored
+449
-71
@@ -2484,6 +2484,11 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
|
||||
++l_current_tile_param;
|
||||
}
|
||||
|
||||
/*Allocate and initialize some elements of codestrem index*/
|
||||
if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) {
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MH;
|
||||
opj_image_comp_header_update(l_image, l_cp);
|
||||
|
||||
@@ -3657,21 +3662,29 @@ static OPJ_BOOL opj_j2k_read_tlm(opj_j2k_t *p_j2k,
|
||||
opj_event_mgr_t * p_manager
|
||||
)
|
||||
{
|
||||
OPJ_UINT32 l_Ztlm, l_Stlm, l_ST, l_SP, l_tot_num_tp_remaining, l_quotient,
|
||||
l_Ptlm_size;
|
||||
OPJ_UINT32 l_Ztlm, l_Stlm, l_ST, l_SP,
|
||||
l_Ptlm_size, l_entry_size, l_num_tileparts;
|
||||
OPJ_UINT32 i;
|
||||
opj_j2k_tlm_tile_part_info_t* l_tile_part_infos;
|
||||
opj_j2k_tlm_info_t* l_tlm;
|
||||
|
||||
/* preconditions */
|
||||
assert(p_header_data != 00);
|
||||
assert(p_j2k != 00);
|
||||
assert(p_manager != 00);
|
||||
|
||||
OPJ_UNUSED(p_j2k);
|
||||
l_tlm = &(p_j2k->m_specific_param.m_decoder.m_tlm);
|
||||
|
||||
if (p_header_size < 2) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Error reading TLM marker\n");
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Error reading TLM marker.\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
p_header_size -= 2;
|
||||
|
||||
if (l_tlm->m_is_invalid) {
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
opj_read_bytes(p_header_data, &l_Ztlm,
|
||||
1); /* Ztlm */
|
||||
++p_header_data;
|
||||
@@ -3680,27 +3693,83 @@ static OPJ_BOOL opj_j2k_read_tlm(opj_j2k_t *p_j2k,
|
||||
++p_header_data;
|
||||
|
||||
l_ST = ((l_Stlm >> 4) & 0x3);
|
||||
if (l_ST == 3) {
|
||||
l_tlm->m_is_invalid = OPJ_TRUE;
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"opj_j2k_read_tlm(): ST = 3 is invalid.\n");
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
l_SP = (l_Stlm >> 6) & 0x1;
|
||||
|
||||
l_Ptlm_size = (l_SP + 1) * 2;
|
||||
l_quotient = l_Ptlm_size + l_ST;
|
||||
l_entry_size = l_Ptlm_size + l_ST;
|
||||
|
||||
l_tot_num_tp_remaining = p_header_size % l_quotient;
|
||||
|
||||
if (l_tot_num_tp_remaining != 0) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Error reading TLM marker\n");
|
||||
return OPJ_FALSE;
|
||||
if ((p_header_size % l_entry_size) != 0) {
|
||||
l_tlm->m_is_invalid = OPJ_TRUE;
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"opj_j2k_read_tlm(): TLM marker not of expected size.\n");
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
/* FIXME Do not care of this at the moment since only local variables are set here */
|
||||
/*
|
||||
for
|
||||
(i = 0; i < l_tot_num_tp; ++i)
|
||||
{
|
||||
opj_read_bytes(p_header_data,&l_Ttlm_i,l_ST); // Ttlm_i
|
||||
|
||||
l_num_tileparts = p_header_size / l_entry_size;
|
||||
if (l_num_tileparts == 0) {
|
||||
/* not totally sure if this is valid... */
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
/* Highly unlikely, unless there are gazillions of TLM markers */
|
||||
if (l_tlm->m_entries_count > UINT32_MAX - l_num_tileparts ||
|
||||
l_tlm->m_entries_count + l_num_tileparts > UINT32_MAX / sizeof(
|
||||
opj_j2k_tlm_tile_part_info_t)) {
|
||||
l_tlm->m_is_invalid = OPJ_TRUE;
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"opj_j2k_read_tlm(): too many TLM markers.\n");
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
l_tile_part_infos = (opj_j2k_tlm_tile_part_info_t*)opj_realloc(
|
||||
l_tlm->m_tile_part_infos,
|
||||
(l_tlm->m_entries_count + l_num_tileparts) * sizeof(
|
||||
opj_j2k_tlm_tile_part_info_t));
|
||||
if (!l_tile_part_infos) {
|
||||
l_tlm->m_is_invalid = OPJ_TRUE;
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"opj_j2k_read_tlm(): cannot allocate m_tile_part_infos.\n");
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
l_tlm->m_tile_part_infos = l_tile_part_infos;
|
||||
|
||||
for (i = 0; i < l_num_tileparts; ++ i) {
|
||||
OPJ_UINT32 l_tile_index;
|
||||
OPJ_UINT32 l_length;
|
||||
|
||||
/* Read Ttlm_i */
|
||||
if (l_ST == 0) {
|
||||
l_tile_index = l_tlm->m_entries_count;
|
||||
} else {
|
||||
opj_read_bytes(p_header_data, &l_tile_index, l_ST);
|
||||
p_header_data += l_ST;
|
||||
opj_read_bytes(p_header_data,&l_Ptlm_i,l_Ptlm_size); // Ptlm_i
|
||||
p_header_data += l_Ptlm_size;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (l_tile_index >= p_j2k->m_cp.tw * p_j2k->m_cp.th) {
|
||||
l_tlm->m_is_invalid = OPJ_TRUE;
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"opj_j2k_read_tlm(): invalid tile number %d\n",
|
||||
l_tile_index);
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
/* Read Ptlm_i */
|
||||
opj_read_bytes(p_header_data, &l_length, l_Ptlm_size);
|
||||
p_header_data += l_Ptlm_size;
|
||||
|
||||
l_tile_part_infos[l_tlm->m_entries_count].m_tile_index =
|
||||
(OPJ_UINT16)l_tile_index;
|
||||
l_tile_part_infos[l_tlm->m_entries_count].m_length = l_length;
|
||||
++l_tlm->m_entries_count;
|
||||
}
|
||||
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
@@ -4583,14 +4652,26 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k,
|
||||
}
|
||||
|
||||
/* Index */
|
||||
if (p_j2k->cstr_index) {
|
||||
{
|
||||
assert(p_j2k->cstr_index->tile_index != 00);
|
||||
p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tileno =
|
||||
p_j2k->m_current_tile_number;
|
||||
p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_tpsno =
|
||||
l_current_part;
|
||||
|
||||
if (l_num_parts != 0) {
|
||||
if (!p_j2k->m_specific_param.m_decoder.m_tlm.m_is_invalid &&
|
||||
l_num_parts >
|
||||
p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].nb_tps) {
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"SOT marker for tile %u declares more tile-parts than found in TLM marker.",
|
||||
p_j2k->m_current_tile_number);
|
||||
p_j2k->m_specific_param.m_decoder.m_tlm.m_is_invalid = OPJ_TRUE;
|
||||
}
|
||||
|
||||
if (!p_j2k->m_specific_param.m_decoder.m_tlm.m_is_invalid) {
|
||||
/* do nothing */
|
||||
} else if (l_num_parts != 0) {
|
||||
|
||||
p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].nb_tps =
|
||||
l_num_parts;
|
||||
p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps =
|
||||
@@ -4661,33 +4742,6 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k,
|
||||
|
||||
}
|
||||
|
||||
/* FIXME move this onto a separate method to call before reading any SOT, remove part about main_end header, use a index struct inside p_j2k */
|
||||
/* if (p_j2k->cstr_info) {
|
||||
if (l_tcp->first) {
|
||||
if (tileno == 0) {
|
||||
p_j2k->cstr_info->main_head_end = p_stream_tell(p_stream) - 13;
|
||||
}
|
||||
|
||||
p_j2k->cstr_info->tile[tileno].tileno = tileno;
|
||||
p_j2k->cstr_info->tile[tileno].start_pos = p_stream_tell(p_stream) - 12;
|
||||
p_j2k->cstr_info->tile[tileno].end_pos = p_j2k->cstr_info->tile[tileno].start_pos + totlen - 1;
|
||||
p_j2k->cstr_info->tile[tileno].num_tps = numparts;
|
||||
|
||||
if (numparts) {
|
||||
p_j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(numparts * sizeof(opj_tp_info_t));
|
||||
}
|
||||
else {
|
||||
p_j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(10 * sizeof(opj_tp_info_t)); // Fixme (10)
|
||||
}
|
||||
}
|
||||
else {
|
||||
p_j2k->cstr_info->tile[tileno].end_pos += totlen;
|
||||
}
|
||||
|
||||
p_j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos = p_stream_tell(p_stream) - 12;
|
||||
p_j2k->cstr_info->tile[tileno].tp[partno].tp_end_pos =
|
||||
p_j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos + totlen - 1;
|
||||
}*/
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
@@ -5023,7 +5077,7 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k,
|
||||
|
||||
/* Index */
|
||||
l_cstr_index = p_j2k->cstr_index;
|
||||
if (l_cstr_index) {
|
||||
{
|
||||
OPJ_OFF_T l_current_pos = opj_stream_tell(p_stream) - 2;
|
||||
|
||||
OPJ_UINT32 l_current_tile_part =
|
||||
@@ -5059,6 +5113,11 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k,
|
||||
}
|
||||
|
||||
if (l_current_read_size != p_j2k->m_specific_param.m_decoder.m_sot_length) {
|
||||
if (l_current_read_size == (OPJ_SIZE_T)(-1)) {
|
||||
/* Avoid issue of https://github.com/uclouvain/openjpeg/issues/1533 */
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC;
|
||||
} else {
|
||||
p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT;
|
||||
@@ -6705,6 +6764,9 @@ void opj_j2k_decoder_set_strict_mode(opj_j2k_t *j2k, OPJ_BOOL strict)
|
||||
{
|
||||
if (j2k) {
|
||||
j2k->m_cp.strict = strict;
|
||||
if (strict) {
|
||||
j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8251,7 +8313,14 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k,
|
||||
tccp->qmfbid = parameters->irreversible ? 0 : 1;
|
||||
tccp->qntsty = parameters->irreversible ? J2K_CCP_QNTSTY_SEQNT :
|
||||
J2K_CCP_QNTSTY_NOQNT;
|
||||
tccp->numgbits = 2;
|
||||
|
||||
if (OPJ_IS_CINEMA(parameters->rsiz) &&
|
||||
parameters->rsiz == OPJ_PROFILE_CINEMA_2K) {
|
||||
/* From https://github.com/uclouvain/openjpeg/issues/1340 */
|
||||
tccp->numgbits = 1;
|
||||
} else {
|
||||
tccp->numgbits = 2;
|
||||
}
|
||||
|
||||
if ((OPJ_INT32)i == parameters->roi_compno) {
|
||||
tccp->roishift = parameters->roi_shift;
|
||||
@@ -8390,7 +8459,8 @@ static OPJ_BOOL opj_j2k_add_tlmarker(OPJ_UINT32 tileno,
|
||||
if (type == J2K_MS_SOT) {
|
||||
OPJ_UINT32 l_current_tile_part = cstr_index->tile_index[tileno].current_tpsno;
|
||||
|
||||
if (cstr_index->tile_index[tileno].tp_index) {
|
||||
if (cstr_index->tile_index[tileno].tp_index &&
|
||||
l_current_tile_part < cstr_index->tile_index[tileno].nb_tps) {
|
||||
cstr_index->tile_index[tileno].tp_index[l_current_tile_part].start_pos = pos;
|
||||
}
|
||||
|
||||
@@ -8467,13 +8537,6 @@ OPJ_BOOL opj_j2k_read_header(opj_stream_private_t *p_stream,
|
||||
/* Copy codestream image information to the output image */
|
||||
opj_copy_image_header(p_j2k->m_private_image, *p_image);
|
||||
|
||||
/*Allocate and initialize some elements of codestrem index*/
|
||||
if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) {
|
||||
opj_image_destroy(*p_image);
|
||||
*p_image = NULL;
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
@@ -8825,6 +8888,87 @@ static OPJ_BOOL opj_j2k_decoding_validation(opj_j2k_t *p_j2k,
|
||||
return l_is_valid;
|
||||
}
|
||||
|
||||
/** Fill p_j2k->cstr_index->tp_index[].start_pos/end_pos fields from TLM marker segments */
|
||||
static void opj_j2k_build_tp_index_from_tlm(opj_j2k_t* p_j2k,
|
||||
opj_event_mgr_t * p_manager)
|
||||
{
|
||||
opj_j2k_tlm_info_t* l_tlm;
|
||||
OPJ_UINT32 i;
|
||||
OPJ_OFF_T l_cur_offset;
|
||||
|
||||
assert(p_j2k->cstr_index->main_head_end > 0);
|
||||
assert(p_j2k->cstr_index->nb_of_tiles > 0);
|
||||
assert(p_j2k->cstr_index->tile_index != NULL);
|
||||
|
||||
l_tlm = &(p_j2k->m_specific_param.m_decoder.m_tlm);
|
||||
|
||||
if (l_tlm->m_entries_count == 0) {
|
||||
l_tlm->m_is_invalid = OPJ_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (l_tlm->m_is_invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initial pass to count the number of tile-parts per tile */
|
||||
for (i = 0; i < l_tlm->m_entries_count; ++i) {
|
||||
OPJ_UINT32 l_tile_index_no = l_tlm->m_tile_part_infos[i].m_tile_index;
|
||||
assert(l_tile_index_no < p_j2k->cstr_index->nb_of_tiles);
|
||||
p_j2k->cstr_index->tile_index[l_tile_index_no].tileno = l_tile_index_no;
|
||||
++p_j2k->cstr_index->tile_index[l_tile_index_no].current_nb_tps;
|
||||
}
|
||||
|
||||
/* Now check that all tiles have at least one tile-part */
|
||||
for (i = 0; i < p_j2k->cstr_index->nb_of_tiles; ++i) {
|
||||
if (p_j2k->cstr_index->tile_index[i].current_nb_tps == 0) {
|
||||
opj_event_msg(p_manager, EVT_ERROR,
|
||||
"opj_j2k_build_tp_index_from_tlm(): tile %d has no "
|
||||
"registered tile-part in TLM marker segments.\n", i);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Final pass to fill p_j2k->cstr_index */
|
||||
l_cur_offset = p_j2k->cstr_index->main_head_end;
|
||||
for (i = 0; i < l_tlm->m_entries_count; ++i) {
|
||||
OPJ_UINT32 l_tile_index_no = l_tlm->m_tile_part_infos[i].m_tile_index;
|
||||
opj_tile_index_t* l_tile_index = &
|
||||
(p_j2k->cstr_index->tile_index[l_tile_index_no]);
|
||||
if (!l_tile_index->tp_index) {
|
||||
l_tile_index->tp_index = (opj_tp_index_t *) opj_calloc(
|
||||
l_tile_index->current_nb_tps, sizeof(opj_tp_index_t));
|
||||
if (! l_tile_index->tp_index) {
|
||||
opj_event_msg(p_manager, EVT_ERROR,
|
||||
"opj_j2k_build_tp_index_from_tlm(): tile index allocation failed\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
assert(l_tile_index->nb_tps < l_tile_index->current_nb_tps);
|
||||
l_tile_index->tp_index[l_tile_index->nb_tps].start_pos = l_cur_offset;
|
||||
/* We don't know how to set the tp_index[].end_header field, but this is not really needed */
|
||||
/* If there would be no markers between SOT and SOD, that would be : */
|
||||
/* l_tile_index->tp_index[l_tile_index->nb_tps].end_header = l_cur_offset + 12; */
|
||||
l_tile_index->tp_index[l_tile_index->nb_tps].end_pos = l_cur_offset +
|
||||
l_tlm->m_tile_part_infos[i].m_length;
|
||||
++l_tile_index->nb_tps;
|
||||
|
||||
l_cur_offset += l_tlm->m_tile_part_infos[i].m_length;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
l_tlm->m_is_invalid = OPJ_TRUE;
|
||||
for (i = 0; i < l_tlm->m_entries_count; ++i) {
|
||||
OPJ_UINT32 l_tile_index = l_tlm->m_tile_part_infos[i].m_tile_index;
|
||||
p_j2k->cstr_index->tile_index[l_tile_index].current_nb_tps = 0;
|
||||
opj_free(p_j2k->cstr_index->tile_index[l_tile_index].tp_index);
|
||||
p_j2k->cstr_index->tile_index[l_tile_index].tp_index = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static OPJ_BOOL opj_j2k_read_header_procedure(opj_j2k_t *p_j2k,
|
||||
opj_stream_private_t *p_stream,
|
||||
opj_event_mgr_t * p_manager)
|
||||
@@ -9004,6 +9148,9 @@ static OPJ_BOOL opj_j2k_read_header_procedure(opj_j2k_t *p_j2k,
|
||||
/* Position of the last element if the main header */
|
||||
p_j2k->cstr_index->main_head_end = (OPJ_UINT32) opj_stream_tell(p_stream) - 2;
|
||||
|
||||
/* Build tile-part index from TLM information */
|
||||
opj_j2k_build_tp_index_from_tlm(p_j2k, p_manager);
|
||||
|
||||
/* Next step: read a tile-part header */
|
||||
p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT;
|
||||
|
||||
@@ -9227,6 +9374,12 @@ void opj_j2k_destroy(opj_j2k_t *p_j2k)
|
||||
p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode = 00;
|
||||
p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = 0;
|
||||
|
||||
opj_free(p_j2k->m_specific_param.m_decoder.m_tlm.m_tile_part_infos);
|
||||
p_j2k->m_specific_param.m_decoder.m_tlm.m_tile_part_infos = NULL;
|
||||
|
||||
opj_free(p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset);
|
||||
p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset = NULL;
|
||||
|
||||
} else {
|
||||
|
||||
if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) {
|
||||
@@ -9577,6 +9730,39 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k,
|
||||
while ((!p_j2k->m_specific_param.m_decoder.m_can_decode) &&
|
||||
(l_current_marker != J2K_MS_EOC)) {
|
||||
|
||||
if (p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts > 0 &&
|
||||
p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts <
|
||||
p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts) {
|
||||
OPJ_OFF_T next_tp_sot_pos;
|
||||
|
||||
next_tp_sot_pos =
|
||||
p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset[p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts];
|
||||
++p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts;
|
||||
if (!(opj_stream_read_seek(p_stream,
|
||||
next_tp_sot_pos,
|
||||
p_manager))) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
/* Try to read 2 bytes (the marker ID) from stream and copy them into the buffer */
|
||||
if (opj_stream_read_data(p_stream,
|
||||
p_j2k->m_specific_param.m_decoder.m_header_data, 2, p_manager) != 2) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
/* Read 2 bytes from the buffer as the marker ID */
|
||||
opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,
|
||||
&l_current_marker,
|
||||
2);
|
||||
|
||||
if (l_current_marker != J2K_MS_SOT) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Did not get expected SOT marker\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to read until the Start Of Data is detected */
|
||||
while (l_current_marker != J2K_MS_SOD) {
|
||||
|
||||
@@ -9610,7 +9796,13 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k,
|
||||
}
|
||||
|
||||
/* Why this condition? FIXME */
|
||||
if (p_j2k->m_specific_param.m_decoder.m_state & J2K_STATE_TPH) {
|
||||
if ((p_j2k->m_specific_param.m_decoder.m_state & J2K_STATE_TPH) &&
|
||||
p_j2k->m_specific_param.m_decoder.m_sot_length != 0) {
|
||||
if (p_j2k->m_specific_param.m_decoder.m_sot_length < l_marker_size + 2) {
|
||||
opj_event_msg(p_manager, EVT_ERROR,
|
||||
"Sot length is less than marker size + marker ID\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
p_j2k->m_specific_param.m_decoder.m_sot_length -= (l_marker_size + 2);
|
||||
}
|
||||
l_marker_size -= 2; /* Subtract the size of the marker ID already read */
|
||||
@@ -9720,14 +9912,78 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k,
|
||||
if (! opj_j2k_read_sod(p_j2k, p_stream, p_manager)) {
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
/* Check if we can use the TLM index to access the next tile-part */
|
||||
if (!p_j2k->m_specific_param.m_decoder.m_can_decode &&
|
||||
p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec >= 0 &&
|
||||
p_j2k->m_current_tile_number == (OPJ_UINT32)
|
||||
p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec &&
|
||||
!p_j2k->m_specific_param.m_decoder.m_tlm.m_is_invalid &&
|
||||
opj_stream_has_seek(p_stream)) {
|
||||
l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number;
|
||||
if (l_tcp->m_nb_tile_parts ==
|
||||
p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].nb_tps &&
|
||||
(OPJ_UINT32)l_tcp->m_current_tile_part_number + 1 < l_tcp->m_nb_tile_parts) {
|
||||
const OPJ_OFF_T next_tp_sot_pos = p_j2k->cstr_index->tile_index[
|
||||
p_j2k->m_current_tile_number].tp_index[l_tcp->m_current_tile_part_number +
|
||||
1].start_pos;
|
||||
|
||||
if (next_tp_sot_pos != opj_stream_tell(p_stream)) {
|
||||
#if 0
|
||||
opj_event_msg(p_manager, EVT_INFO,
|
||||
"opj_j2k_read_tile_header(tile=%u): seek to tile part %u at %" PRId64 "\n",
|
||||
p_j2k->m_current_tile_number,
|
||||
l_tcp->m_current_tile_part_number + 1,
|
||||
next_tp_sot_pos);
|
||||
#endif
|
||||
|
||||
if (!(opj_stream_read_seek(p_stream,
|
||||
next_tp_sot_pos,
|
||||
p_manager))) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to read 2 bytes (the marker ID) from stream and copy them into the buffer */
|
||||
if (opj_stream_read_data(p_stream,
|
||||
p_j2k->m_specific_param.m_decoder.m_header_data, 2, p_manager) != 2) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
/* Read 2 bytes from the buffer as the marker ID */
|
||||
opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,
|
||||
&l_current_marker,
|
||||
2);
|
||||
|
||||
if (l_current_marker != J2K_MS_SOT) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Did not get expected SOT marker\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_j2k->m_specific_param.m_decoder.m_can_decode &&
|
||||
!p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked) {
|
||||
/* Issue 254 */
|
||||
OPJ_BOOL l_correction_needed;
|
||||
OPJ_BOOL l_correction_needed = OPJ_FALSE;
|
||||
|
||||
p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked = 1;
|
||||
if (!opj_j2k_need_nb_tile_parts_correction(p_stream,
|
||||
p_j2k->m_current_tile_number, &l_correction_needed, p_manager)) {
|
||||
if (p_j2k->m_cp.tcps[p_j2k->m_current_tile_number].m_nb_tile_parts == 1) {
|
||||
/* Skip opj_j2k_need_nb_tile_parts_correction() if there is
|
||||
* only a single tile part declared. The
|
||||
* opj_j2k_need_nb_tile_parts_correction() hack was needed
|
||||
* for files with 5 declared tileparts (where they were
|
||||
* actually 6).
|
||||
* Doing it systematically hurts performance when reading
|
||||
* Sentinel2 L1C JPEG2000 files as explained in
|
||||
* https://lists.osgeo.org/pipermail/gdal-dev/2024-November/059805.html
|
||||
*/
|
||||
} else if (!opj_j2k_need_nb_tile_parts_correction(p_stream,
|
||||
p_j2k->m_current_tile_number, &l_correction_needed, p_manager)) {
|
||||
opj_event_msg(p_manager, EVT_ERROR,
|
||||
"opj_j2k_apply_nb_tile_parts_correction error\n");
|
||||
return OPJ_FALSE;
|
||||
@@ -11303,6 +11559,17 @@ static void opj_j2k_dump_MH_index(opj_j2k_t* p_j2k, FILE* out_stream)
|
||||
OPJ_UINT32 l_acc_nb_of_tile_part = 0;
|
||||
for (it_tile = 0; it_tile < cstr_index->nb_of_tiles ; it_tile++) {
|
||||
l_acc_nb_of_tile_part += cstr_index->tile_index[it_tile].nb_tps;
|
||||
|
||||
/* To avoid regenerating expected opj_dump results from the test */
|
||||
/* suite when there is a TLM marker present */
|
||||
if (cstr_index->tile_index[it_tile].nb_tps &&
|
||||
cstr_index->tile_index[it_tile].tp_index &&
|
||||
cstr_index->tile_index[it_tile].tp_index[0].start_pos > 0 &&
|
||||
cstr_index->tile_index[it_tile].tp_index[0].end_header == 0 &&
|
||||
getenv("OJP_DO_NOT_DISPLAY_TILE_INDEX_IF_TLM") != NULL) {
|
||||
l_acc_nb_of_tile_part = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (l_acc_nb_of_tile_part) {
|
||||
@@ -11666,6 +11933,18 @@ static OPJ_BOOL opj_j2k_are_all_used_components_decoded(opj_j2k_t *p_j2k,
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
static int CompareOffT(const void* a, const void* b)
|
||||
{
|
||||
const OPJ_OFF_T offA = *(const OPJ_OFF_T*)a;
|
||||
const OPJ_OFF_T offB = *(const OPJ_OFF_T*)b;
|
||||
if (offA < offB) {
|
||||
return -1;
|
||||
}
|
||||
if (offA == offB) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
|
||||
opj_stream_private_t *p_stream,
|
||||
@@ -11676,6 +11955,7 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
|
||||
OPJ_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1;
|
||||
OPJ_UINT32 l_nb_comps;
|
||||
OPJ_UINT32 nr_tiles = 0;
|
||||
OPJ_OFF_T end_pos = 0;
|
||||
|
||||
/* Particular case for whole single tile decoding */
|
||||
/* We can avoid allocating intermediate tile buffers */
|
||||
@@ -11698,8 +11978,9 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0,
|
||||
p_stream, p_manager)) {
|
||||
if (!l_go_on ||
|
||||
! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0,
|
||||
p_stream, p_manager)) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Failed to decode tile 1/1\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
@@ -11717,6 +11998,77 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts = 0;
|
||||
p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts = 0;
|
||||
opj_free(p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset);
|
||||
p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset = NULL;
|
||||
|
||||
/* If the area to decode only intersects a subset of tiles, and we have
|
||||
* valid TLM information, then use it to plan the tilepart offsets to
|
||||
* seek to.
|
||||
*/
|
||||
if (!(p_j2k->m_specific_param.m_decoder.m_start_tile_x == 0 &&
|
||||
p_j2k->m_specific_param.m_decoder.m_start_tile_y == 0 &&
|
||||
p_j2k->m_specific_param.m_decoder.m_end_tile_x == p_j2k->m_cp.tw &&
|
||||
p_j2k->m_specific_param.m_decoder.m_end_tile_y == p_j2k->m_cp.th) &&
|
||||
!p_j2k->m_specific_param.m_decoder.m_tlm.m_is_invalid &&
|
||||
opj_stream_has_seek(p_stream)) {
|
||||
OPJ_UINT32 m_num_intersecting_tile_parts = 0;
|
||||
|
||||
OPJ_UINT32 j;
|
||||
for (j = 0; j < p_j2k->m_cp.tw * p_j2k->m_cp.th; ++j) {
|
||||
if (p_j2k->cstr_index->tile_index[j].nb_tps > 0 &&
|
||||
p_j2k->cstr_index->tile_index[j].tp_index[
|
||||
p_j2k->cstr_index->tile_index[j].nb_tps - 1].end_pos > end_pos) {
|
||||
end_pos = p_j2k->cstr_index->tile_index[j].tp_index[
|
||||
p_j2k->cstr_index->tile_index[j].nb_tps - 1].end_pos;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = p_j2k->m_specific_param.m_decoder.m_start_tile_y;
|
||||
j < p_j2k->m_specific_param.m_decoder.m_end_tile_y; ++j) {
|
||||
OPJ_UINT32 i;
|
||||
for (i = p_j2k->m_specific_param.m_decoder.m_start_tile_x;
|
||||
i < p_j2k->m_specific_param.m_decoder.m_end_tile_x; ++i) {
|
||||
const OPJ_UINT32 tile_number = j * p_j2k->m_cp.tw + i;
|
||||
m_num_intersecting_tile_parts +=
|
||||
p_j2k->cstr_index->tile_index[tile_number].nb_tps;
|
||||
}
|
||||
}
|
||||
|
||||
p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset =
|
||||
(OPJ_OFF_T*)
|
||||
opj_malloc(m_num_intersecting_tile_parts * sizeof(OPJ_OFF_T));
|
||||
if (m_num_intersecting_tile_parts > 0 &&
|
||||
p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset) {
|
||||
OPJ_UINT32 idx = 0;
|
||||
for (j = p_j2k->m_specific_param.m_decoder.m_start_tile_y;
|
||||
j < p_j2k->m_specific_param.m_decoder.m_end_tile_y; ++j) {
|
||||
OPJ_UINT32 i;
|
||||
for (i = p_j2k->m_specific_param.m_decoder.m_start_tile_x;
|
||||
i < p_j2k->m_specific_param.m_decoder.m_end_tile_x; ++i) {
|
||||
const OPJ_UINT32 tile_number = j * p_j2k->m_cp.tw + i;
|
||||
OPJ_UINT32 k;
|
||||
for (k = 0; k < p_j2k->cstr_index->tile_index[tile_number].nb_tps; ++k) {
|
||||
const OPJ_OFF_T next_tp_sot_pos =
|
||||
p_j2k->cstr_index->tile_index[tile_number].tp_index[k].start_pos;
|
||||
p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset[idx] =
|
||||
next_tp_sot_pos;
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts = idx;
|
||||
|
||||
/* Sort by increasing offset */
|
||||
qsort(p_j2k->m_specific_param.m_decoder.m_intersecting_tile_parts_offset,
|
||||
p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts,
|
||||
sizeof(OPJ_OFF_T),
|
||||
CompareOffT);
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 &&
|
||||
p_j2k->m_cp.tcps[0].m_data != NULL) {
|
||||
@@ -11776,6 +12128,12 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
|
||||
if (++nr_tiles == p_j2k->m_cp.th * p_j2k->m_cp.tw) {
|
||||
break;
|
||||
}
|
||||
if (p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts > 0 &&
|
||||
p_j2k->m_specific_param.m_decoder.m_idx_intersecting_tile_parts ==
|
||||
p_j2k->m_specific_param.m_decoder.m_num_intersecting_tile_parts) {
|
||||
opj_stream_seek(p_stream, end_pos + 2, p_manager);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! opj_j2k_are_all_used_components_decoded(p_j2k, p_manager)) {
|
||||
@@ -11819,12 +12177,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k,
|
||||
OPJ_UINT32 l_nb_tiles;
|
||||
OPJ_UINT32 i;
|
||||
|
||||
/*Allocate and initialize some elements of codestrem index if not already done*/
|
||||
if (!p_j2k->cstr_index->tile_index) {
|
||||
if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) {
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
}
|
||||
/* Move into the codestream to the first SOT used to decode the desired tile */
|
||||
l_tile_no_to_dec = (OPJ_UINT32)
|
||||
p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec;
|
||||
@@ -11839,12 +12191,38 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k,
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
} else {
|
||||
OPJ_OFF_T sot_pos =
|
||||
p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos;
|
||||
OPJ_UINT32 l_marker;
|
||||
|
||||
#if 0
|
||||
opj_event_msg(p_manager, EVT_INFO,
|
||||
"opj_j2k_decode_one_tile(%u): seek to %" PRId64 "\n",
|
||||
l_tile_no_to_dec,
|
||||
sot_pos);
|
||||
#endif
|
||||
if (!(opj_stream_read_seek(p_stream,
|
||||
p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos + 2,
|
||||
sot_pos,
|
||||
p_manager))) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
/* Try to read 2 bytes (the marker ID) from stream and copy them into the buffer */
|
||||
if (opj_stream_read_data(p_stream,
|
||||
p_j2k->m_specific_param.m_decoder.m_header_data, 2, p_manager) != 2) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
/* Read 2 bytes from the buffer as the marker ID */
|
||||
opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data, &l_marker,
|
||||
2);
|
||||
|
||||
if (l_marker != J2K_MS_SOT) {
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Did not get expected SOT marker\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
}
|
||||
/* Special case if we have previously read the EOC marker (if the previous tile getted is the last ) */
|
||||
if (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_EOC) {
|
||||
|
||||
Vendored
+30
@@ -466,6 +466,24 @@ typedef struct opj_cp {
|
||||
/* <<UniPG */
|
||||
} opj_cp_t;
|
||||
|
||||
/** Entry of a TLM marker segment */
|
||||
typedef struct opj_j2k_tlm_tile_part_info {
|
||||
/** Tile index of the tile part. Ttlmi field */
|
||||
OPJ_UINT16 m_tile_index;
|
||||
/** Length in bytes, from the beginning of the SOT marker to the end of
|
||||
* the bit stream data for that tile-part. Ptlmi field */
|
||||
OPJ_UINT32 m_length;
|
||||
} opj_j2k_tlm_tile_part_info_t;
|
||||
|
||||
/** Information got from the concatenation of TLM marker semgnets. */
|
||||
typedef struct opj_j2k_tlm_info {
|
||||
/** Number of entries in m_tile_part_infos. */
|
||||
OPJ_UINT32 m_entries_count;
|
||||
/** Array of m_entries_count values. */
|
||||
opj_j2k_tlm_tile_part_info_t* m_tile_part_infos;
|
||||
|
||||
OPJ_BOOL m_is_invalid;
|
||||
} opj_j2k_tlm_info_t;
|
||||
|
||||
typedef struct opj_j2k_dec {
|
||||
/** locate in which part of the codestream the decoder is (main header, tile header, end) */
|
||||
@@ -499,6 +517,18 @@ typedef struct opj_j2k_dec {
|
||||
OPJ_UINT32 m_numcomps_to_decode;
|
||||
OPJ_UINT32 *m_comps_indices_to_decode;
|
||||
|
||||
opj_j2k_tlm_info_t m_tlm;
|
||||
|
||||
/** Below if used when there's TLM information available and we use
|
||||
* opj_set_decoded_area() to a subset of all tiles.
|
||||
*/
|
||||
/* Current index in m_intersecting_tile_parts_offset[] to seek to */
|
||||
OPJ_UINT32 m_idx_intersecting_tile_parts;
|
||||
/* Number of elements of m_intersecting_tile_parts_offset[] */
|
||||
OPJ_UINT32 m_num_intersecting_tile_parts;
|
||||
/* Start offset of contributing tile parts */
|
||||
OPJ_OFF_T* m_intersecting_tile_parts_offset;
|
||||
|
||||
/** to tell that a tile can be decoded. */
|
||||
OPJ_BITFIELD m_can_decode : 1;
|
||||
OPJ_BITFIELD m_discard_tiles : 1;
|
||||
|
||||
Vendored
+8
-4
@@ -1989,12 +1989,16 @@ OPJ_BOOL opj_jp2_setup_encoder(opj_jp2_t *jp2,
|
||||
jp2->enumcs = 0;
|
||||
} else {
|
||||
jp2->meth = 1;
|
||||
if (image->color_space == 1) {
|
||||
if (image->color_space == OPJ_CLRSPC_SRGB) {
|
||||
jp2->enumcs = 16; /* sRGB as defined by IEC 61966-2-1 */
|
||||
} else if (image->color_space == 2) {
|
||||
jp2->enumcs = 17; /* greyscale */
|
||||
} else if (image->color_space == 3) {
|
||||
} else if (image->color_space == OPJ_CLRSPC_GRAY) {
|
||||
jp2->enumcs = 17;
|
||||
} else if (image->color_space == OPJ_CLRSPC_SYCC) {
|
||||
jp2->enumcs = 18; /* YUV */
|
||||
} else if (image->color_space == OPJ_CLRSPC_EYCC) {
|
||||
jp2->enumcs = 24;
|
||||
} else if (image->color_space == OPJ_CLRSPC_CMYK) {
|
||||
jp2->enumcs = 12;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+9
-5
@@ -546,7 +546,7 @@ typedef struct opj_cparameters {
|
||||
} opj_cparameters_t;
|
||||
|
||||
#define OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG 0x0001
|
||||
#define OPJ_DPARAMETERS_DUMP_FLAG 0x0002
|
||||
#define OPJ_DPARAMETERS_DUMP_FLAG 0x0002
|
||||
|
||||
/**
|
||||
* Decompression parameters
|
||||
@@ -772,7 +772,7 @@ typedef struct opj_packet_info {
|
||||
OPJ_OFF_T end_ph_pos;
|
||||
/** packet end position */
|
||||
OPJ_OFF_T end_pos;
|
||||
/** packet distorsion */
|
||||
/** packet distortion */
|
||||
double disto;
|
||||
} opj_packet_info_t;
|
||||
|
||||
@@ -1348,9 +1348,13 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec,
|
||||
opj_dparameters_t *parameters);
|
||||
|
||||
/**
|
||||
* Set strict decoding parameter for this decoder. If strict decoding is enabled, partial bit
|
||||
* streams will fail to decode. If strict decoding is disabled, the decoder will decode partial
|
||||
* bitstreams as much as possible without erroring
|
||||
* Set strict decoding parameter for this decoder.
|
||||
* If strict decoding is enabled, partial bit streams will fail to decode, and
|
||||
* the check for invalid TPSOT values added in https://github.com/uclouvain/openjpeg/pull/514
|
||||
* will be disabled.
|
||||
* If strict decoding is disabled, the decoder will decode partial
|
||||
* bitstreams as much as possible without erroring, and the TPSOT fixing logic
|
||||
* will be enabled.
|
||||
*
|
||||
* @param p_codec decompressor handler
|
||||
* @param strict OPJ_TRUE to enable strict decoding, OPJ_FALSE to disable
|
||||
|
||||
+3
-3
@@ -28,8 +28,8 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef OPJ_COMMMON_H
|
||||
#define OPJ_COMMMON_H
|
||||
#ifndef OPJ_COMMON_H
|
||||
#define OPJ_COMMON_H
|
||||
|
||||
/*
|
||||
==========================================================
|
||||
@@ -44,4 +44,4 @@
|
||||
#define OPJ_COMP_PARAM_DEFAULT_PROG_ORDER OPJ_LRCP
|
||||
#define OPJ_COMP_PARAM_DEFAULT_NUMRESOLUTION 6
|
||||
|
||||
#endif /* OPJ_COMMMON_H */
|
||||
#endif /* OPJ_COMMON_H */
|
||||
|
||||
Vendored
+151
-2
@@ -47,6 +47,9 @@
|
||||
#ifdef __SSE2__
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
#if (defined(__AVX2__) || defined(__AVX512F__))
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC poison malloc calloc realloc free
|
||||
@@ -1796,6 +1799,39 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
|
||||
OPJ_INT32* OPJ_RESTRICT tiledp = &tilec->data[(OPJ_SIZE_T)y * tile_w +
|
||||
(OPJ_SIZE_T)x];
|
||||
for (j = 0; j < cblk_h; ++j) {
|
||||
//positive -> round down aka. (83)/2 = 41.5 -> 41
|
||||
//negative -> round up aka. (-83)/2 = -41.5 -> -41
|
||||
#if defined(__AVX512F__)
|
||||
OPJ_INT32* ptr_in = datap + (j * cblk_w);
|
||||
OPJ_INT32* ptr_out = tiledp + (j * (OPJ_SIZE_T)tile_w);
|
||||
for (i = 0; i < cblk_w / 16; ++i) {
|
||||
__m512i in_avx = _mm512_loadu_si512((__m512i*)(ptr_in));
|
||||
const __m512i add_avx = _mm512_srli_epi32(in_avx, 31);
|
||||
in_avx = _mm512_add_epi32(in_avx, add_avx);
|
||||
_mm512_storeu_si512((__m512i*)(ptr_out), _mm512_srai_epi32(in_avx, 1));
|
||||
ptr_in += 16;
|
||||
ptr_out += 16;
|
||||
}
|
||||
|
||||
for (i = 0; i < cblk_w % 16; ++i) {
|
||||
ptr_out[i] = ptr_in[i] / 2;
|
||||
}
|
||||
#elif defined(__AVX2__)
|
||||
OPJ_INT32* ptr_in = datap + (j * cblk_w);
|
||||
OPJ_INT32* ptr_out = tiledp + (j * (OPJ_SIZE_T)tile_w);
|
||||
for (i = 0; i < cblk_w / 8; ++i) {
|
||||
__m256i in_avx = _mm256_loadu_si256((__m256i*)(ptr_in));
|
||||
const __m256i add_avx = _mm256_srli_epi32(in_avx, 31);
|
||||
in_avx = _mm256_add_epi32(in_avx, add_avx);
|
||||
_mm256_storeu_si256((__m256i*)(ptr_out), _mm256_srai_epi32(in_avx, 1));
|
||||
ptr_in += 8;
|
||||
ptr_out += 8;
|
||||
}
|
||||
|
||||
for (i = 0; i < cblk_w % 8; ++i) {
|
||||
ptr_out[i] = ptr_in[i] / 2;
|
||||
}
|
||||
#else
|
||||
i = 0;
|
||||
for (; i < (cblk_w & ~(OPJ_UINT32)3U); i += 4U) {
|
||||
OPJ_INT32 tmp0 = datap[(j * cblk_w) + i + 0U];
|
||||
@@ -1811,6 +1847,7 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
|
||||
OPJ_INT32 tmp = datap[(j * cblk_w) + i];
|
||||
((OPJ_INT32*)tiledp)[(j * (OPJ_SIZE_T)tile_w) + i] = tmp / 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else { /* if (tccp->qmfbid == 0) */
|
||||
const float stepsize = 0.5f * band->stepsize;
|
||||
@@ -2006,10 +2043,16 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
|
||||
opj_mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3);
|
||||
opj_mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4);
|
||||
|
||||
if (cblk->corrupted) {
|
||||
assert(cblk->numchunks == 0);
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
/* Even if we have a single chunk, in multi-threaded decoding */
|
||||
/* the insertion of our synthetic marker might potentially override */
|
||||
/* valid codestream of other codeblocks decoded in parallel. */
|
||||
if (cblk->numchunks > 1 || t1->mustuse_cblkdatabuffer) {
|
||||
if (cblk->numchunks > 1 || (t1->mustuse_cblkdatabuffer &&
|
||||
cblk->numchunks > 0)) {
|
||||
OPJ_UINT32 i;
|
||||
OPJ_UINT32 cblk_len;
|
||||
|
||||
@@ -2124,7 +2167,7 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
|
||||
opj_mutex_lock(p_manager_mutex);
|
||||
}
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"PTERM check failure: %d synthetized 0xFF markers read\n",
|
||||
"PTERM check failure: %d synthesized 0xFF markers read\n",
|
||||
mqc->end_of_byte_stream_counter);
|
||||
if (p_manager_mutex) {
|
||||
opj_mutex_unlock(p_manager_mutex);
|
||||
@@ -2227,6 +2270,111 @@ static void opj_t1_cblk_encode_processor(void* user_data, opj_tls_t* tls)
|
||||
OPJ_UINT32* OPJ_RESTRICT t1data = (OPJ_UINT32*) t1->data;
|
||||
/* Change from "natural" order to "zigzag" order of T1 passes */
|
||||
for (j = 0; j < (cblk_h & ~3U); j += 4) {
|
||||
#if defined(__AVX512F__)
|
||||
const __m512i perm1 = _mm512_setr_epi64(2, 3, 10, 11, 4, 5, 12, 13);
|
||||
const __m512i perm2 = _mm512_setr_epi64(6, 7, 14, 15, 0, 0, 0, 0);
|
||||
OPJ_UINT32* ptr = tiledp_u;
|
||||
for (i = 0; i < cblk_w / 16; ++i) {
|
||||
// INPUT OUTPUT
|
||||
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 10 20 30 01 11 21 31 02 12 22 32 03 13 23 33
|
||||
// 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 04 14 24 34 05 15 25 35 06 16 26 36 07 17 27 37
|
||||
// 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 08 18 28 38 09 19 29 39 0A 1A 2A 3A 0B 1B 2B 3B
|
||||
// 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 0C 1C 2C 3C 0D 1D 2D 3D 0E 1E 2E 3E 0F 1F 2F 3F
|
||||
__m512i in1 = _mm512_slli_epi32(_mm512_loadu_si512((__m512i*)(ptr +
|
||||
(j + 0) * tile_w)), T1_NMSEDEC_FRACBITS);
|
||||
__m512i in2 = _mm512_slli_epi32(_mm512_loadu_si512((__m512i*)(ptr +
|
||||
(j + 1) * tile_w)), T1_NMSEDEC_FRACBITS);
|
||||
__m512i in3 = _mm512_slli_epi32(_mm512_loadu_si512((__m512i*)(ptr +
|
||||
(j + 2) * tile_w)), T1_NMSEDEC_FRACBITS);
|
||||
__m512i in4 = _mm512_slli_epi32(_mm512_loadu_si512((__m512i*)(ptr +
|
||||
(j + 3) * tile_w)), T1_NMSEDEC_FRACBITS);
|
||||
|
||||
__m512i tmp1 = _mm512_unpacklo_epi32(in1, in2);
|
||||
__m512i tmp2 = _mm512_unpacklo_epi32(in3, in4);
|
||||
__m512i tmp3 = _mm512_unpackhi_epi32(in1, in2);
|
||||
__m512i tmp4 = _mm512_unpackhi_epi32(in3, in4);
|
||||
|
||||
in1 = _mm512_unpacklo_epi64(tmp1, tmp2);
|
||||
in2 = _mm512_unpacklo_epi64(tmp3, tmp4);
|
||||
in3 = _mm512_unpackhi_epi64(tmp1, tmp2);
|
||||
in4 = _mm512_unpackhi_epi64(tmp3, tmp4);
|
||||
|
||||
_mm_storeu_si128((__m128i*)(t1data + 0), _mm512_castsi512_si128(in1));
|
||||
_mm_storeu_si128((__m128i*)(t1data + 4), _mm512_castsi512_si128(in3));
|
||||
_mm_storeu_si128((__m128i*)(t1data + 8), _mm512_castsi512_si128(in2));
|
||||
_mm_storeu_si128((__m128i*)(t1data + 12), _mm512_castsi512_si128(in4));
|
||||
|
||||
tmp1 = _mm512_permutex2var_epi64(in1, perm1, in3);
|
||||
tmp2 = _mm512_permutex2var_epi64(in2, perm1, in4);
|
||||
|
||||
_mm256_storeu_si256((__m256i*)(t1data + 16), _mm512_castsi512_si256(tmp1));
|
||||
_mm256_storeu_si256((__m256i*)(t1data + 24), _mm512_castsi512_si256(tmp2));
|
||||
_mm256_storeu_si256((__m256i*)(t1data + 32), _mm512_extracti64x4_epi64(tmp1,
|
||||
0x1));
|
||||
_mm256_storeu_si256((__m256i*)(t1data + 40), _mm512_extracti64x4_epi64(tmp2,
|
||||
0x1));
|
||||
_mm256_storeu_si256((__m256i*)(t1data + 48),
|
||||
_mm512_castsi512_si256(_mm512_permutex2var_epi64(in1, perm2, in3)));
|
||||
_mm256_storeu_si256((__m256i*)(t1data + 56),
|
||||
_mm512_castsi512_si256(_mm512_permutex2var_epi64(in2, perm2, in4)));
|
||||
t1data += 64;
|
||||
ptr += 16;
|
||||
}
|
||||
for (i = 0; i < cblk_w % 16; ++i) {
|
||||
t1data[0] = ptr[(j + 0) * tile_w] << T1_NMSEDEC_FRACBITS;
|
||||
t1data[1] = ptr[(j + 1) * tile_w] << T1_NMSEDEC_FRACBITS;
|
||||
t1data[2] = ptr[(j + 2) * tile_w] << T1_NMSEDEC_FRACBITS;
|
||||
t1data[3] = ptr[(j + 3) * tile_w] << T1_NMSEDEC_FRACBITS;
|
||||
t1data += 4;
|
||||
ptr += 1;
|
||||
}
|
||||
#elif defined(__AVX2__)
|
||||
OPJ_UINT32* ptr = tiledp_u;
|
||||
for (i = 0; i < cblk_w / 8; ++i) {
|
||||
// INPUT OUTPUT
|
||||
// 00 01 02 03 04 05 06 07 00 10 20 30 01 11 21 31
|
||||
// 10 11 12 13 14 15 16 17 02 12 22 32 03 13 23 33
|
||||
// 20 21 22 23 24 25 26 27 04 14 24 34 05 15 25 35
|
||||
// 30 31 32 33 34 35 36 37 06 16 26 36 07 17 27 37
|
||||
__m256i in1 = _mm256_slli_epi32(_mm256_loadu_si256((__m256i*)(ptr +
|
||||
(j + 0) * tile_w)), T1_NMSEDEC_FRACBITS);
|
||||
__m256i in2 = _mm256_slli_epi32(_mm256_loadu_si256((__m256i*)(ptr +
|
||||
(j + 1) * tile_w)), T1_NMSEDEC_FRACBITS);
|
||||
__m256i in3 = _mm256_slli_epi32(_mm256_loadu_si256((__m256i*)(ptr +
|
||||
(j + 2) * tile_w)), T1_NMSEDEC_FRACBITS);
|
||||
__m256i in4 = _mm256_slli_epi32(_mm256_loadu_si256((__m256i*)(ptr +
|
||||
(j + 3) * tile_w)), T1_NMSEDEC_FRACBITS);
|
||||
|
||||
__m256i tmp1 = _mm256_unpacklo_epi32(in1, in2);
|
||||
__m256i tmp2 = _mm256_unpacklo_epi32(in3, in4);
|
||||
__m256i tmp3 = _mm256_unpackhi_epi32(in1, in2);
|
||||
__m256i tmp4 = _mm256_unpackhi_epi32(in3, in4);
|
||||
|
||||
in1 = _mm256_unpacklo_epi64(tmp1, tmp2);
|
||||
in2 = _mm256_unpacklo_epi64(tmp3, tmp4);
|
||||
in3 = _mm256_unpackhi_epi64(tmp1, tmp2);
|
||||
in4 = _mm256_unpackhi_epi64(tmp3, tmp4);
|
||||
|
||||
_mm_storeu_si128((__m128i*)(t1data + 0), _mm256_castsi256_si128(in1));
|
||||
_mm_storeu_si128((__m128i*)(t1data + 4), _mm256_castsi256_si128(in3));
|
||||
_mm_storeu_si128((__m128i*)(t1data + 8), _mm256_castsi256_si128(in2));
|
||||
_mm_storeu_si128((__m128i*)(t1data + 12), _mm256_castsi256_si128(in4));
|
||||
_mm256_storeu_si256((__m256i*)(t1data + 16), _mm256_permute2x128_si256(in1, in3,
|
||||
0x31));
|
||||
_mm256_storeu_si256((__m256i*)(t1data + 24), _mm256_permute2x128_si256(in2, in4,
|
||||
0x31));
|
||||
t1data += 32;
|
||||
ptr += 8;
|
||||
}
|
||||
for (i = 0; i < cblk_w % 8; ++i) {
|
||||
t1data[0] = ptr[(j + 0) * tile_w] << T1_NMSEDEC_FRACBITS;
|
||||
t1data[1] = ptr[(j + 1) * tile_w] << T1_NMSEDEC_FRACBITS;
|
||||
t1data[2] = ptr[(j + 2) * tile_w] << T1_NMSEDEC_FRACBITS;
|
||||
t1data[3] = ptr[(j + 3) * tile_w] << T1_NMSEDEC_FRACBITS;
|
||||
t1data += 4;
|
||||
ptr += 1;
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < cblk_w; ++i) {
|
||||
t1data[0] = tiledp_u[(j + 0) * tile_w + i] << T1_NMSEDEC_FRACBITS;
|
||||
t1data[1] = tiledp_u[(j + 1) * tile_w + i] << T1_NMSEDEC_FRACBITS;
|
||||
@@ -2234,6 +2382,7 @@ static void opj_t1_cblk_encode_processor(void* user_data, opj_tls_t* tls)
|
||||
t1data[3] = tiledp_u[(j + 3) * tile_w + i] << T1_NMSEDEC_FRACBITS;
|
||||
t1data += 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (j < cblk_h) {
|
||||
for (i = 0; i < cblk_w; ++i) {
|
||||
|
||||
Vendored
+35
-25
@@ -1111,6 +1111,7 @@ static OPJ_BOOL opj_t2_read_packet_header(opj_t2_t* p_t2,
|
||||
/* SOP markers */
|
||||
|
||||
if (p_tcp->csty & J2K_CP_CSTY_SOP) {
|
||||
/* SOP markers are allowed (i.e. optional), just warn */
|
||||
if (p_max_length < 6) {
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"Not enough space for expected SOP marker\n");
|
||||
@@ -1163,12 +1164,15 @@ static OPJ_BOOL opj_t2_read_packet_header(opj_t2_t* p_t2,
|
||||
|
||||
/* EPH markers */
|
||||
if (p_tcp->csty & J2K_CP_CSTY_EPH) {
|
||||
/* EPH markers are required */
|
||||
if ((*l_modified_length_ptr - (OPJ_UINT32)(l_header_data -
|
||||
*l_header_data_start)) < 2U) {
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"Not enough space for expected EPH marker\n");
|
||||
opj_event_msg(p_manager, EVT_ERROR,
|
||||
"Not enough space for required EPH marker\n");
|
||||
return OPJ_FALSE;
|
||||
} else if ((*l_header_data) != 0xff || (*(l_header_data + 1) != 0x92)) {
|
||||
opj_event_msg(p_manager, EVT_WARNING, "Expected EPH marker\n");
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Expected EPH marker\n");
|
||||
return OPJ_FALSE;
|
||||
} else {
|
||||
l_header_data += 2;
|
||||
}
|
||||
@@ -1340,12 +1344,15 @@ static OPJ_BOOL opj_t2_read_packet_header(opj_t2_t* p_t2,
|
||||
|
||||
/* EPH markers */
|
||||
if (p_tcp->csty & J2K_CP_CSTY_EPH) {
|
||||
/* EPH markers are required */
|
||||
if ((*l_modified_length_ptr - (OPJ_UINT32)(l_header_data -
|
||||
*l_header_data_start)) < 2U) {
|
||||
opj_event_msg(p_manager, EVT_WARNING,
|
||||
"Not enough space for expected EPH marker\n");
|
||||
opj_event_msg(p_manager, EVT_ERROR,
|
||||
"Not enough space for required EPH marker\n");
|
||||
return OPJ_FALSE;
|
||||
} else if ((*l_header_data) != 0xff || (*(l_header_data + 1) != 0x92)) {
|
||||
opj_event_msg(p_manager, EVT_WARNING, "Expected EPH marker\n");
|
||||
opj_event_msg(p_manager, EVT_ERROR, "Expected EPH marker\n");
|
||||
return OPJ_FALSE;
|
||||
} else {
|
||||
l_header_data += 2;
|
||||
}
|
||||
@@ -1353,6 +1360,9 @@ static OPJ_BOOL opj_t2_read_packet_header(opj_t2_t* p_t2,
|
||||
|
||||
l_header_length = (OPJ_UINT32)(l_header_data - *l_header_data_start);
|
||||
JAS_FPRINTF(stderr, "hdrlen=%d \n", l_header_length);
|
||||
if (!l_header_length) {
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
JAS_FPRINTF(stderr, "packet body\n");
|
||||
*l_modified_length_ptr -= l_header_length;
|
||||
*l_header_data_start += l_header_length;
|
||||
@@ -1404,18 +1414,21 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2,
|
||||
l_nb_code_blocks = l_prc->cw * l_prc->ch;
|
||||
l_cblk = l_prc->cblks.dec;
|
||||
|
||||
for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) {
|
||||
for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno, ++l_cblk) {
|
||||
opj_tcd_seg_t *l_seg = 00;
|
||||
|
||||
// if we have a partial data stream, set numchunks to zero
|
||||
// since we have no data to actually decode.
|
||||
if (partial_buffer) {
|
||||
l_cblk->numchunks = 0;
|
||||
}
|
||||
|
||||
if (!l_cblk->numnewpasses) {
|
||||
/* nothing to do */
|
||||
++l_cblk;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (partial_buffer || l_cblk->corrupted) {
|
||||
/* if a previous segment in this packet couldn't be decoded,
|
||||
* or if this code block was corrupted in a previous layer,
|
||||
* then mark it as corrupted.
|
||||
*/
|
||||
l_cblk->numchunks = 0;
|
||||
l_cblk->corrupted = OPJ_TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1448,18 +1461,13 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2,
|
||||
"read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
|
||||
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno,
|
||||
p_pi->compno);
|
||||
// skip this codeblock since it is a partial read
|
||||
/* skip this codeblock (and following ones in this
|
||||
* packet) since it is a partial read
|
||||
*/
|
||||
partial_buffer = OPJ_TRUE;
|
||||
l_cblk->corrupted = OPJ_TRUE;
|
||||
l_cblk->numchunks = 0;
|
||||
|
||||
l_seg->numpasses += l_seg->numnewpasses;
|
||||
l_cblk->numnewpasses -= l_seg->numnewpasses;
|
||||
if (l_cblk->numnewpasses > 0) {
|
||||
++l_seg;
|
||||
++l_cblk->numsegs;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1516,7 +1524,7 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2,
|
||||
} while (l_cblk->numnewpasses > 0);
|
||||
|
||||
l_cblk->real_num_segs = l_cblk->numsegs;
|
||||
++l_cblk;
|
||||
|
||||
} /* next code_block */
|
||||
|
||||
++l_band;
|
||||
@@ -1600,6 +1608,8 @@ static OPJ_BOOL opj_t2_skip_packet_data(opj_t2_t* p_t2,
|
||||
"skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
|
||||
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno,
|
||||
p_pi->compno);
|
||||
|
||||
*p_data_read = p_max_length;
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -243,7 +243,7 @@ void opj_tcd_rateallocate_fixed(opj_tcd_t *tcd)
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/** Returns OPJ_TRUE if the layer allocation is unchanged w.r.t to the previous
|
||||
* invokation with a different threshold */
|
||||
* invocation with a different threshold */
|
||||
static
|
||||
OPJ_BOOL opj_tcd_makelayer(opj_tcd_t *tcd,
|
||||
OPJ_UINT32 layno,
|
||||
@@ -2861,12 +2861,12 @@ OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd,
|
||||
return intersects;
|
||||
}
|
||||
|
||||
/** Returns whether a tile componenent is fully decoded, taking into account
|
||||
/** Returns whether a tile component is fully decoded, taking into account
|
||||
* p_tcd->win_* members.
|
||||
*
|
||||
* @param p_tcd TCD handle.
|
||||
* @param compno Component number
|
||||
* @return OPJ_TRUE whether the tile componenent is fully decoded
|
||||
* @return OPJ_TRUE whether the tile component is fully decoded
|
||||
*/
|
||||
static OPJ_BOOL opj_tcd_is_whole_tilecomp_decoding(opj_tcd_t *p_tcd,
|
||||
OPJ_UINT32 compno)
|
||||
|
||||
Vendored
+4
-3
@@ -141,6 +141,7 @@ typedef struct opj_tcd_cblk_dec {
|
||||
OPJ_UINT32 numchunksalloc; /* Number of chunks item allocated */
|
||||
/* Decoded code-block. Only used for subtile decoding. Otherwise tilec->data is directly updated */
|
||||
OPJ_INT32* decoded_data;
|
||||
OPJ_BOOL corrupted; /* whether the code block data is corrupted */
|
||||
} opj_tcd_cblk_dec_t;
|
||||
|
||||
/** Precinct structure */
|
||||
@@ -312,7 +313,7 @@ typedef struct opj_tcd_marker_info {
|
||||
/**
|
||||
Dump the content of a tcd structure
|
||||
*/
|
||||
/*void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t *img);*/ /* TODO MSD shoul use the new v2 structures */
|
||||
/*void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t *img);*/ /* TODO MSD should use the new v2 structures */
|
||||
|
||||
/**
|
||||
Create a new TCD handle
|
||||
@@ -443,7 +444,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd,
|
||||
OPJ_SIZE_T opj_tcd_get_encoder_input_buffer_size(opj_tcd_t *p_tcd);
|
||||
|
||||
/**
|
||||
* Initialize the tile coder and may reuse some meory.
|
||||
* Initialize the tile coder and may reuse some memory.
|
||||
*
|
||||
* @param p_tcd TCD handle.
|
||||
* @param p_tile_no current tile index to encode.
|
||||
@@ -491,7 +492,7 @@ void opj_tcd_reinit_segment(opj_tcd_seg_t* seg);
|
||||
* @param y0 Upper left y in subband coordinates
|
||||
* @param x1 Lower right x in subband coordinates
|
||||
* @param y1 Lower right y in subband coordinates
|
||||
* @return OPJ_TRUE whether the sub-band region contributs to the area of
|
||||
* @return OPJ_TRUE whether the sub-band region contributes to the area of
|
||||
* interest.
|
||||
*/
|
||||
OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd,
|
||||
|
||||
+6
-1
@@ -657,6 +657,7 @@ if(UNIX OR MINGW)
|
||||
endif()
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFile)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckSymbolExists)
|
||||
|
||||
if(NOT APPLE)
|
||||
@@ -668,7 +669,11 @@ if(UNIX OR MINGW)
|
||||
elseif(EMSCRIPTEN)
|
||||
# no need to link to system libs with emscripten
|
||||
elseif(QNXNTO)
|
||||
set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} m regex)
|
||||
set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} m)
|
||||
CHECK_LIBRARY_EXISTS(regex regexec "" HAVE_REGEX_LIBRARY)
|
||||
if(HAVE_REGEX_LIBRARY)
|
||||
set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} regex)
|
||||
endif()
|
||||
elseif(MINGW)
|
||||
set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} pthread)
|
||||
else()
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
Building OpenCV with FastCV {#tutorial_building_fastcv}
|
||||
===========================
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Compatibility | OpenCV >= 4.11.0 |
|
||||
|
||||
Enable OpenCV with FastCV for Qualcomm Chipsets
|
||||
-----------------------------------------------
|
||||
|
||||
This document scope is to guide the Developers to enable OpenCV Acceleration with FastCV for the
|
||||
Qualcomm chipsets with ARM64 architecture. Entablement of OpenCV with FastCV back-end on non-Qualcomm
|
||||
chipsets or Linux platforms other than [Qualcomm Linux](https://www.qualcomm.com/developer/software/qualcomm-linux)
|
||||
is currently out of scope.
|
||||
|
||||
About FastCV
|
||||
------------
|
||||
|
||||
FastCV provides two main features to computer vision application developers:
|
||||
|
||||
- A library of frequently used computer vision (CV) functions, optimized to run efficiently on a wide variety of Qualcomm’s Snapdragon devices.
|
||||
- A clean processor-agnostic hardware acceleration API, under which chipset vendors can hardware accelerate FastCV functions on Qualcomm’s Snapdragon hardware.
|
||||
|
||||
FastCV is released as a unified binary, a single binary containing two implementations of the algorithms:
|
||||
|
||||
- Generic implementation runs on Arm® architecture and is referred to as FastCV for Arm architecture.
|
||||
- Implementation runs only on Qualcomm® Snapdragon™ chipsets and is called FastCV for Snapdragon.
|
||||
|
||||
FastCV library is Qualcomm proprietary and provides faster implementation of CV algorithms on various hardware as compared to other CV libraries.
|
||||
|
||||
OpenCV Acceleration with FastCV HAL and Extensions
|
||||
--------------------------------------------------
|
||||
|
||||
OpenCV and FastCV integration is implemented in two ways:
|
||||
|
||||
1. FastCV-based HAL for basic computer vision and arithmetic algorithms acceleration.
|
||||
2. FastCV module in opencv_contrib with custom algorithms and FastCV function wrappers that do not fit generic OpenCV interface or behaviour.
|
||||
|
||||
|
||||

|
||||
|
||||
Supported Platforms
|
||||
-------------------
|
||||
|
||||
1. Android : Qualcomm Chipsets with the Android from Snapdragon 8 Gen 1 onwards(https://www.qualcomm.com/products/mobile/snapdragon/smartphones#product-list)
|
||||
2. Linux : Qualcomm Linux Program related boards mentioned in [Hardware](https://www.qualcomm.com/developer/software/qualcomm-linux/hardware)
|
||||
|
||||
Compiling OpenCV with FastCV for Android
|
||||
----------------------------------------
|
||||
|
||||
1. **Follow Wiki page for OpenCV Compilation** : https://github.com/opencv/opencv/wiki/Custom-OpenCV-Android-SDK-and-AAR-package-build
|
||||
|
||||
Once the OpenCV repository code is cloned into the workspace, please add `-DWITH_FASTCV=ON` flag to cmake vars as below to arm64 entry
|
||||
in `opencv/platforms/android/default.config.py` or create new one with the option to enable FastCV HAL and/or extenstions compilation:
|
||||
|
||||
```
|
||||
ABI("3", "arm64-v8a", None, 24, cmake_vars=dict(WITH_FASTCV='ON')),
|
||||
```
|
||||
|
||||
2. Remaining steps can be followed as mentioned in [the wiki page](https://github.com/opencv/opencv/wiki/Custom-OpenCV-Android-SDK-and-AAR-package-build)
|
||||
|
||||
Compiling OpenCV with FastCV for Qualcomm Linux
|
||||
-----------------------------------------------
|
||||
|
||||
@note: Only Ubuntu 22.04 is supported as host platform for eSDK deployment.
|
||||
|
||||
1. Install eSDK by following [Qualcomm® Linux Documentation](https://docs.qualcomm.com/bundle/publicresource/topics/80-70017-51/install-sdk.html)
|
||||
|
||||
2. After installing the eSDK, set the ESDK_ROOT:
|
||||
|
||||
```
|
||||
export ESDK_ROOT=<eSDK install location>
|
||||
```
|
||||
|
||||
3. Add SDK tools and libraries to your environment:
|
||||
|
||||
```
|
||||
source environment-setup-armv8-2a-qcom-linux
|
||||
```
|
||||
|
||||
If you encounter the following message:
|
||||
```
|
||||
Your environment is misconfigured, you probably need to 'unset LD_LIBRARY_PATH'
|
||||
but please check why this was set in the first place and that it's safe to unset.
|
||||
The SDK will not operate correctly in most cases when LD_LIBRARY_PATH is set.
|
||||
```
|
||||
just unset your host `LD_LIBRARY_PATH` environment variable: `unset LD_LIBRARY_PATH`.
|
||||
|
||||
4. Clone OpenCV Repositories:
|
||||
|
||||
Clone the OpenCV main and optionally opencv_contrib repositories into any directory
|
||||
(it does not need to be inside the SDK directory).
|
||||
|
||||
```
|
||||
git clone https://github.com/opencv/opencv.git
|
||||
git clone https://github.com/opencv/opencv_contrib.git
|
||||
```
|
||||
|
||||
5. Build OpenCV
|
||||
|
||||
Create a build directory, navigate into it and build the project with CMake there:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=aarch64 -DWITH_FASTCV=ON -DBUILD_SHARED_LIBS=ON -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules/fastcv/ ../opencv
|
||||
make -j$(nproc)
|
||||
```
|
||||
|
||||
If the FastCV library is updated, please replace the old FastCV libraries located at:
|
||||
```
|
||||
<ESDK_PATH>\qcom-wayland_sdk\tmp\sysroots\qcs6490-rb3gen2-vision-kit\usr\lib
|
||||
```
|
||||
with the latest FastCV libraries downloaded in:
|
||||
```
|
||||
build\3rdparty\fastcv\libs
|
||||
```
|
||||
|
||||
6. Validate
|
||||
|
||||
Push the OpenCV libraries, test binaries and test data on to the target. Execute the OpenCV conformance or performance tests.
|
||||
During runtime, If libwebp.so.7 lib is missing, find the lib in the below Path and push it on the target
|
||||
```
|
||||
<ESDK_PATH>\qcom-wayland_sdk\tmp\sysroots\qcs6490-rb3gen2-vision-kit\usr\lib\libwebp.so.7
|
||||
```
|
||||
|
||||
HAL and Extension list of APIs
|
||||
------------------------------
|
||||
|
||||
**FastCV based OpenCV HAL APIs list :**
|
||||
|
||||
|OpenCV module |OpenCV API | Underlying FastCV API for OpenCV acceleration |
|
||||
|---------------|------------------|-----------------------------------------------|
|
||||
|IMGPROC |medianBlur |fcvFilterMedian3x3u8_v3 |
|
||||
| |sobel |fcvFilterSobel3x3u8s16 |
|
||||
| | |fcvFilterSobel5x5u8s16 |
|
||||
| | |fcvFilterSobel7x7u8s16 |
|
||||
| |boxFilter |fcvBoxFilter3x3u8_v3 |
|
||||
| | |fcvBoxFilter5x5u8_v2 |
|
||||
| |adaptiveThreshold |fcvAdaptiveThresholdGaussian3x3u8_v2 |
|
||||
| | |fcvAdaptiveThresholdGaussian5x5u8_v2 |
|
||||
| | |fcvAdaptiveThresholdMean3x3u8_v2 |
|
||||
| | |fcvAdaptiveThresholdMean5x5u8_v2 |
|
||||
| |pyrUp & pyrDown |fcvPyramidCreateu8_v4 |
|
||||
| |cvtColor |fcvColorRGB888toYCrCbu8_v3 |
|
||||
| | |fcvColorRGB888ToHSV888u8 |
|
||||
| |GaussianBlur |fcvFilterGaussian5x5u8_v3 |
|
||||
| | |fcvFilterGaussian3x3u8_v4 |
|
||||
| |cvWarpPerspective |fcvWarpPerspectiveu8_v5 |
|
||||
| |Canny |fcvFilterCannyu8 |
|
||||
| | | |
|
||||
|CORE |lut | fcvTableLookupu8 |
|
||||
| |norm |fcvHammingDistanceu8 |
|
||||
| |multiply |fcvElementMultiplyu8u16_v2 |
|
||||
| |transpose |fcvTransposeu8_v2 |
|
||||
| | |fcvTransposeu16_v2 |
|
||||
| | |fcvTransposef32_v2 |
|
||||
| |meanStdDev |fcvImageIntensityStats_v2 |
|
||||
| |flip |fcvFlipu8 |
|
||||
| | |fcvFlipu16 |
|
||||
| | |fcvFlipRGB888u8 |
|
||||
| |rotate |fcvRotateImageu8 |
|
||||
| | |fcvRotateImageInterleavedu8 |
|
||||
| |multiply |fcvElementMultiplyu8 |
|
||||
| | |fcvElementMultiplys16 |
|
||||
| | |fcvElementMultiplyf32 |
|
||||
| |addWeighted |fcvAddWeightedu8_v2 |
|
||||
| |subtract |fcvImageDiffu8f32_v2 |
|
||||
|
||||
|
||||
**FastCV based OpenCV Extensions APIs list :**
|
||||
|
||||
|OpenCV Extension APIs |Underlying FastCV API for OpenCV acceleration |
|
||||
|----------------------|----------------------------------------------|
|
||||
|matmuls8s32 |fcvMatrixMultiplys8s32 |
|
||||
|clusterEuclidean |fcvClusterEuclideanu8 |
|
||||
|FAST10 |fcvCornerFast10InMaskScoreu8 |
|
||||
| |fcvCornerFast10InMasku8 |
|
||||
| |fcvCornerFast10Scoreu8 |
|
||||
| |fcvCornerFast10u8 |
|
||||
|FFT |fcvFFTu8 |
|
||||
|IFFT |fcvIFFTf32 |
|
||||
|fillConvexPoly |fcvFillConvexPolyu8 |
|
||||
|houghLines |fcvHoughLineu8 |
|
||||
|moments |fcvImageMomentsu8 |
|
||||
| |fcvImageMomentss32 |
|
||||
| |fcvImageMomentsf32 |
|
||||
|runMSER |fcvMserInit |
|
||||
| |fcvMserNN8Init |
|
||||
| |fcvMserExtu8_v3 |
|
||||
| |fcvMserExtNN8u8 |
|
||||
| |fcvMserNN8u8 |
|
||||
| |fcvMserRelease |
|
||||
|remap |fcvRemapu8_v2 |
|
||||
|remapRGBA |fcvRemapRGBA8888BLu8 |
|
||||
| |fcvRemapRGBA8888NNu8 |
|
||||
|resizeDownBy2 |fcvScaleDownBy2u8_v2 |
|
||||
|resizeDownBy4 |fcvScaleDownBy4u8_v2 |
|
||||
|meanShift |fcvMeanShiftu8 |
|
||||
| |fcvMeanShifts32 |
|
||||
| |fcvMeanShiftf32 |
|
||||
|bilateralRecursive |fcvBilateralFilterRecursiveu8 |
|
||||
|thresholdRange |fcvFilterThresholdRangeu8_v2 |
|
||||
|bilateralFilter |fcvBilateralFilter5x5u8_v3 |
|
||||
| |fcvBilateralFilter7x7u8_v3 |
|
||||
| |fcvBilateralFilter9x9u8_v3 |
|
||||
|calcHist |fcvImageIntensityHistogram |
|
||||
|gaussianBlur |fcvFilterGaussian3x3u8_v4 |
|
||||
| |fcvFilterGaussian5x5u8_v3 |
|
||||
| |fcvFilterGaussian5x5s16_v3 |
|
||||
| |fcvFilterGaussian5x5s32_v3 |
|
||||
| |fcvFilterGaussian11x11u8_v2 |
|
||||
|filter2D |fcvFilterCorrNxNu8 |
|
||||
| |fcvFilterCorrNxNu8s16 |
|
||||
| |fcvFilterCorrNxNu8f32 |
|
||||
|sepFilter2D |fcvFilterCorrSepMxNu8 |
|
||||
| |fcvFilterCorrSep9x9s16_v2 |
|
||||
| |fcvFilterCorrSep11x11s16_v2 |
|
||||
| |fcvFilterCorrSep13x13s16_v2 |
|
||||
| |fcvFilterCorrSep15x15s16_v2 |
|
||||
| |fcvFilterCorrSep17x17s16_v2 |
|
||||
| |fcvFilterCorrSepNxNs16 |
|
||||
|sobel3x3u8 |fcvImageGradientSobelPlanars8_v2 |
|
||||
|sobel3x3u9 |fcvImageGradientSobelPlanars16_v2 |
|
||||
|sobel3x3u10 |fcvImageGradientSobelPlanars16_v3 |
|
||||
|sobel3x3u11 |fcvImageGradientSobelPlanarf32_v2 |
|
||||
|sobel3x3u12 |fcvImageGradientSobelPlanarf32_v3 |
|
||||
|sobel |fcvFilterSobel3x3u8_v2 |
|
||||
| |fcvFilterSobel3x3u8s16 |
|
||||
| |fcvFilterSobel5x5u8s16 |
|
||||
| |fcvFilterSobel7x7u8s16 |
|
||||
|DCT |fcvDCTu8 |
|
||||
|iDCT |fcvIDCTs16 |
|
||||
|sobelPyramid |fcvPyramidAllocate |
|
||||
| |fcvPyramidAllocate_v2 |
|
||||
| |fcvPyramidAllocate_v3 |
|
||||
| |fcvPyramidSobelGradientCreatei8 |
|
||||
| |fcvPyramidSobelGradientCreatei16 |
|
||||
| |fcvPyramidSobelGradientCreatef32 |
|
||||
| |fcvPyramidDelete |
|
||||
| |fcvPyramidDelete_v2 |
|
||||
| |fcvPyramidCreatef32_v2 |
|
||||
| |fcvPyramidCreateu8_v4 |
|
||||
|trackOpticalFlowLK |fcvTrackLKOpticalFlowu8_v3 |
|
||||
| |fcvTrackLKOpticalFlowu8 |
|
||||
|warpPerspective2Plane |fcv2PlaneWarpPerspectiveu8 |
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -30,6 +30,7 @@ Introduction to OpenCV {#tutorial_table_of_content_introduction}
|
||||
- @subpage tutorial_arm_crosscompile_with_cmake
|
||||
- @subpage tutorial_crosscompile_with_multiarch
|
||||
- @subpage tutorial_building_tegra_cuda
|
||||
- @subpage tutorial_building_fastcv
|
||||
- @ref tutorial_ios_install
|
||||
|
||||
##### Usage basics
|
||||
|
||||
@@ -426,10 +426,18 @@ void cv::fisheye::undistortPoints( InputArray distorted, OutputArray undistorted
|
||||
if ((converged || !isEps) && !theta_flipped)
|
||||
{
|
||||
Vec2d pu = pw * scale; //undistorted point
|
||||
Vec2d fi;
|
||||
|
||||
// reproject
|
||||
Vec3d pr = RR * Vec3d(pu[0], pu[1], 1.0); // rotated point optionally multiplied by new camera matrix
|
||||
Vec2d fi(pr[0]/pr[2], pr[1]/pr[2]); // final
|
||||
if (!R.empty() || !P.empty())
|
||||
{
|
||||
// reproject
|
||||
Vec3d pr = RR * Vec3d(pu[0], pu[1], 1.0); // rotated point optionally multiplied by new camera matrix
|
||||
fi = Vec2d(pr[0]/pr[2], pr[1]/pr[2]); // final
|
||||
}
|
||||
else
|
||||
{
|
||||
fi = pu;
|
||||
}
|
||||
|
||||
if( sdepth == CV_32F )
|
||||
dstf[i] = fi;
|
||||
|
||||
@@ -480,11 +480,14 @@ static void undistortPointsInternal( const Mat& _src, Mat& _dst, const Mat& _cam
|
||||
}
|
||||
}
|
||||
|
||||
double xx = RR[0][0]*x + RR[0][1]*y + RR[0][2];
|
||||
double yy = RR[1][0]*x + RR[1][1]*y + RR[1][2];
|
||||
double ww = 1./(RR[2][0]*x + RR[2][1]*y + RR[2][2]);
|
||||
x = xx*ww;
|
||||
y = yy*ww;
|
||||
if( !matR.empty() || !matP.empty() )
|
||||
{
|
||||
double xx = RR[0][0]*x + RR[0][1]*y + RR[0][2];
|
||||
double yy = RR[1][0]*x + RR[1][1]*y + RR[1][2];
|
||||
double ww = 1./(RR[2][0]*x + RR[2][1]*y + RR[2][2]);
|
||||
x = xx*ww;
|
||||
y = yy*ww;
|
||||
}
|
||||
|
||||
if( dtype == CV_32FC2 )
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ ocv_add_dispatched_file(minmax SSE2 SSE4_1 AVX2 VSX3 LASX)
|
||||
ocv_add_dispatched_file(nan_mask SSE2 AVX2 LASX)
|
||||
ocv_add_dispatched_file(split SSE2 AVX2 LASX)
|
||||
ocv_add_dispatched_file(sum SSE2 AVX2 LASX)
|
||||
ocv_add_dispatched_file(norm SSE2 SSE4_1 AVX AVX2 NEON_DOTPROD LASX)
|
||||
|
||||
# dispatching for accuracy tests
|
||||
ocv_add_dispatched_file_force_all(test_intrin128 TEST SSE2 SSE3 SSSE3 SSE4_1 SSE4_2 AVX FP16 AVX2 AVX512_SKX)
|
||||
|
||||
@@ -706,6 +706,28 @@ INSTANTIATE_TEST_CASE_P(/*nothing*/ , ArithmMixedTest,
|
||||
)
|
||||
);
|
||||
|
||||
typedef perf::TestBaseWithParam<std::tuple<cv::Size, int, bool>> SqrtFixture;
|
||||
PERF_TEST_P_(SqrtFixture, Sqrt) {
|
||||
Size sz = get<0>(GetParam());
|
||||
int type = get<1>(GetParam());
|
||||
bool inverse = get<2>(GetParam());
|
||||
|
||||
Mat src(sz, type), dst(sz, type);
|
||||
randu(src, FLT_EPSILON, 1000);
|
||||
declare.in(src).out(dst);
|
||||
|
||||
TEST_CYCLE() cv::pow(src, inverse ? -0.5 : 0.5, dst);
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/ , SqrtFixture,
|
||||
testing::Combine(
|
||||
testing::Values(TYPICAL_MAT_SIZES),
|
||||
testing::Values(CV_32FC1, CV_64FC1),
|
||||
testing::Bool()
|
||||
)
|
||||
);
|
||||
|
||||
///////////// Rotate ////////////////////////
|
||||
|
||||
typedef perf::TestBaseWithParam<std::tuple<cv::Size, int, perf::MatType>> RotateTest;
|
||||
@@ -862,5 +884,29 @@ INSTANTIATE_TEST_CASE_P(/*nothing*/ , FiniteMaskFixture,
|
||||
)
|
||||
);
|
||||
|
||||
//////////////EXP////////////
|
||||
|
||||
typedef Size_MatType ExpFixture;
|
||||
|
||||
PERF_TEST_P(ExpFixture, Exp,
|
||||
testing::Combine(testing::Values(TYPICAL_MAT_SIZES), testing::Values(CV_32F, CV_64F)))
|
||||
{
|
||||
cv::Size size = std::get<0>(GetParam());
|
||||
int type = std::get<1>(GetParam());
|
||||
|
||||
cv::Mat src(size, type);
|
||||
cv::Mat dst(size, type);
|
||||
|
||||
declare.in(src).out(dst);
|
||||
|
||||
cv::randu(src, -5.0, 5.0);
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
cv::exp(src, dst);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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.
|
||||
|
||||
#include "perf_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
using namespace perf;
|
||||
|
||||
enum
|
||||
{
|
||||
FLIP_XY = 0,
|
||||
FLIP_X = 1,
|
||||
FLIP_Y = 2,
|
||||
};
|
||||
|
||||
#define FLIP_SIZES szQVGA, szVGA, sz1080p
|
||||
#define FLIP_TYPES CV_8UC1, CV_8UC3, CV_8UC4
|
||||
#define FLIP_CODES FLIP_X, FLIP_Y, FLIP_XY
|
||||
|
||||
CV_FLAGS(FlipCode, FLIP_X, FLIP_Y, FLIP_XY);
|
||||
typedef tuple<Size, MatType, FlipCode> Size_MatType_FlipCode_t;
|
||||
typedef perf::TestBaseWithParam<Size_MatType_FlipCode_t> Size_MatType_FlipCode;
|
||||
|
||||
PERF_TEST_P(Size_MatType_FlipCode,
|
||||
flip,
|
||||
testing::Combine(testing::Values(FLIP_SIZES),
|
||||
testing::Values(FLIP_TYPES),
|
||||
testing::Values(FLIP_CODES)))
|
||||
{
|
||||
Size sz = get<0>(GetParam());
|
||||
int matType = get<1>(GetParam());
|
||||
int flipCode = get<2>(GetParam()) - 1;
|
||||
|
||||
Mat src(sz, matType);
|
||||
Mat dst(sz, matType);
|
||||
|
||||
declare.in(src, WARMUP_RNG).out(dst);
|
||||
|
||||
TEST_CYCLE() cv::flip(src, dst, flipCode);
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
}} // namespace opencv_test
|
||||
@@ -340,7 +340,7 @@ void invSqrt32f(const float* src, float* dst, int len)
|
||||
|
||||
int i = 0;
|
||||
|
||||
#if CV_SIMD
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int VECSZ = VTraits<v_float32>::vlanes();
|
||||
for( ; i < len; i += VECSZ*2 )
|
||||
{
|
||||
@@ -368,7 +368,7 @@ void invSqrt64f(const double* src, double* dst, int len)
|
||||
CV_INSTRUMENT_REGION();
|
||||
int i = 0;
|
||||
|
||||
#if CV_SIMD_64F
|
||||
#if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F)
|
||||
const int VECSZ = VTraits<v_float64>::vlanes();
|
||||
for ( ; i < len; i += VECSZ*2)
|
||||
{
|
||||
@@ -396,7 +396,7 @@ void sqrt32f(const float* src, float* dst, int len)
|
||||
|
||||
int i = 0;
|
||||
|
||||
#if CV_SIMD
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int VECSZ = VTraits<v_float32>::vlanes();
|
||||
for( ; i < len; i += VECSZ*2 )
|
||||
{
|
||||
@@ -425,7 +425,7 @@ void sqrt64f(const double* src, double* dst, int len)
|
||||
|
||||
int i = 0;
|
||||
|
||||
#if CV_SIMD_64F
|
||||
#if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F)
|
||||
const int VECSZ = VTraits<v_float64>::vlanes();
|
||||
for( ; i < len; i += VECSZ*2 )
|
||||
{
|
||||
@@ -527,7 +527,7 @@ void exp32f( const float *_x, float *y, int n )
|
||||
float maxval = (float)(exp_max_val/exp_prescale);
|
||||
float postscale = (float)exp_postscale;
|
||||
|
||||
#if CV_SIMD
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int VECSZ = VTraits<v_float32>::vlanes();
|
||||
const v_float32 vprescale = vx_setall_f32((float)exp_prescale);
|
||||
const v_float32 vpostscale = vx_setall_f32((float)exp_postscale);
|
||||
@@ -641,7 +641,7 @@ void exp64f( const double *_x, double *y, int n )
|
||||
double minval = (-exp_max_val/exp_prescale);
|
||||
double maxval = (exp_max_val/exp_prescale);
|
||||
|
||||
#if CV_SIMD_64F
|
||||
#if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F)
|
||||
const int VECSZ = VTraits<v_float64>::vlanes();
|
||||
const v_float64 vprescale = vx_setall_f64(exp_prescale);
|
||||
const v_float64 vpostscale = vx_setall_f64(exp_postscale);
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include "opencl_kernels_core.hpp"
|
||||
#include "stat.hpp"
|
||||
|
||||
#include "norm.simd.hpp"
|
||||
#include "norm.simd_declarations.hpp"
|
||||
|
||||
/****************************************************************************************\
|
||||
* norm *
|
||||
\****************************************************************************************/
|
||||
@@ -215,127 +218,6 @@ int normL1_(const uchar* a, const uchar* b, int n)
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
template<typename T, typename ST> int
|
||||
normInf_(const T* src, const uchar* mask, ST* _result, int len, int cn)
|
||||
{
|
||||
ST result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
result = std::max(result, normInf<T, ST>(src, len*cn));
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
result = std::max(result, (ST)cv_abs(src[k]));
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename ST> int
|
||||
normL1_(const T* src, const uchar* mask, ST* _result, int len, int cn)
|
||||
{
|
||||
ST result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
result += normL1<T, ST>(src, len*cn);
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
result += cv_abs(src[k]);
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename ST> int
|
||||
normL2_(const T* src, const uchar* mask, ST* _result, int len, int cn)
|
||||
{
|
||||
ST result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
result += normL2Sqr<T, ST>(src, len*cn);
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
{
|
||||
ST v = (ST)src[k];
|
||||
result += v*v;
|
||||
}
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
normInf_Bool(const uchar* src, const uchar* mask, int* _result, int len, int cn)
|
||||
{
|
||||
int result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
for ( int i = 0; i < len*cn; i++ ) {
|
||||
result = std::max(result, (int)(src[i] != 0));
|
||||
if (result != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
result = std::max(result, (int)(src[k] != 0));
|
||||
if (result != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
normL1_Bool(const uchar* src, const uchar* mask, int* _result, int len, int cn)
|
||||
{
|
||||
int result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
for ( int i = 0; i < len*cn; i++ )
|
||||
result += (int)(src[i] != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
result += (int)(src[k] != 0);
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
normL2_Bool(const uchar* src, const uchar* mask, int* _result, int len, int cn)
|
||||
{
|
||||
return normL1_Bool(src, mask, _result, len, cn);
|
||||
}
|
||||
|
||||
template<typename T, typename ST> int
|
||||
normDiffInf_(const T* src1, const T* src2, const uchar* mask, ST* _result, int len, int cn)
|
||||
{
|
||||
@@ -457,141 +339,68 @@ normDiffL2_Bool(const uchar* src1, const uchar* src2, const uchar* mask, int* _r
|
||||
return normDiffL1_Bool(src1, src2, mask, _result, len, cn);
|
||||
}
|
||||
|
||||
#define CV_DEF_NORM_FUNC(L, suffix, type, ntype) \
|
||||
static int norm##L##_##suffix(const type* src, const uchar* mask, ntype* r, int len, int cn) \
|
||||
{ return norm##L##_<type, ntype>(src, mask, r, len, cn); } \
|
||||
#define CV_DEF_NORM_DIFF_FUNC(L, suffix, type, ntype) \
|
||||
static int normDiff##L##_##suffix(const type* src1, const type* src2, \
|
||||
const uchar* mask, ntype* r, int len, int cn) \
|
||||
{ return normDiff##L##_<type, ntype>(src1, src2, mask, r, (int)len, cn); }
|
||||
{ return normDiff##L##_(src1, src2, mask, r, (int)len, cn); }
|
||||
|
||||
#define CV_DEF_NORM_ALL(suffix, type, inftype, l1type, l2type) \
|
||||
CV_DEF_NORM_FUNC(Inf, suffix, type, inftype) \
|
||||
CV_DEF_NORM_FUNC(L1, suffix, type, l1type) \
|
||||
CV_DEF_NORM_FUNC(L2, suffix, type, l2type)
|
||||
#define CV_DEF_NORM_DIFF_ALL(suffix, type, inftype, l1type, l2type) \
|
||||
CV_DEF_NORM_DIFF_FUNC(Inf, suffix, type, inftype) \
|
||||
CV_DEF_NORM_DIFF_FUNC(L1, suffix, type, l1type) \
|
||||
CV_DEF_NORM_DIFF_FUNC(L2, suffix, type, l2type)
|
||||
|
||||
CV_DEF_NORM_ALL(8u, uchar, int, int, int)
|
||||
CV_DEF_NORM_ALL(8s, schar, int, int, int)
|
||||
CV_DEF_NORM_ALL(16u, ushort, int, int, double)
|
||||
CV_DEF_NORM_ALL(16s, short, int, int, double)
|
||||
CV_DEF_NORM_ALL(32u, unsigned, unsigned, double, double)
|
||||
CV_DEF_NORM_ALL(32s, int, unsigned, double, double)
|
||||
CV_DEF_NORM_ALL(32f, float, float, double, double)
|
||||
CV_DEF_NORM_ALL(64f, double, double, double, double)
|
||||
CV_DEF_NORM_ALL(64u, uint64, uint64, double, double)
|
||||
CV_DEF_NORM_ALL(64s, int64, uint64, double, double)
|
||||
CV_DEF_NORM_ALL(16f, hfloat, float, float, float)
|
||||
CV_DEF_NORM_ALL(16bf, bfloat, float, float, float)
|
||||
CV_DEF_NORM_DIFF_ALL(8u, uchar, int, int, int)
|
||||
CV_DEF_NORM_DIFF_ALL(8s, schar, int, int, int)
|
||||
CV_DEF_NORM_DIFF_ALL(16u, ushort, int, int, double)
|
||||
CV_DEF_NORM_DIFF_ALL(16s, short, int, int, double)
|
||||
CV_DEF_NORM_DIFF_ALL(32u, unsigned, unsigned, double, double)
|
||||
CV_DEF_NORM_DIFF_ALL(32s, int, int, double, double)
|
||||
CV_DEF_NORM_DIFF_ALL(32f, float, float, double, double)
|
||||
CV_DEF_NORM_DIFF_ALL(64f, double, double, double, double)
|
||||
CV_DEF_NORM_DIFF_ALL(64u, uint64, uint64, double, double)
|
||||
CV_DEF_NORM_DIFF_ALL(64s, int64, uint64, double, double)
|
||||
CV_DEF_NORM_DIFF_ALL(16f, hfloat, float, float, float)
|
||||
CV_DEF_NORM_DIFF_ALL(16bf, bfloat, float, float, float)
|
||||
|
||||
typedef int (*NormFunc)(const uchar*, const uchar*, void*, int, int);
|
||||
typedef int (*NormDiffFunc)(const uchar*, const uchar*, const uchar*, void*, int, int);
|
||||
|
||||
static NormFunc getNormFunc(int normType, int depth)
|
||||
{
|
||||
static NormFunc normTab[3][CV_DEPTH_MAX] =
|
||||
{
|
||||
{
|
||||
(NormFunc)GET_OPTIMIZED(normInf_8u),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_8s),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_16u),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_16s),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_32s),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_32f),
|
||||
(NormFunc)normInf_64f,
|
||||
(NormFunc)GET_OPTIMIZED(normInf_16f),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_16bf),
|
||||
(NormFunc)normInf_Bool,
|
||||
(NormFunc)GET_OPTIMIZED(normInf_64u),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_64s),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_32u),
|
||||
0
|
||||
},
|
||||
{
|
||||
(NormFunc)GET_OPTIMIZED(normL1_8u),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_8s),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_16u),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_16s),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_32s),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_32f),
|
||||
(NormFunc)normL1_64f,
|
||||
(NormFunc)GET_OPTIMIZED(normL1_16f),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_16bf),
|
||||
(NormFunc)normL1_Bool,
|
||||
(NormFunc)GET_OPTIMIZED(normL1_64u),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_64s),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_32u),
|
||||
0
|
||||
},
|
||||
{
|
||||
(NormFunc)GET_OPTIMIZED(normL2_8u),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_8s),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_16u),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_16s),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_32s),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_32f),
|
||||
(NormFunc)normL2_64f,
|
||||
(NormFunc)GET_OPTIMIZED(normL2_16f),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_16bf),
|
||||
(NormFunc)normL2_Bool,
|
||||
(NormFunc)GET_OPTIMIZED(normL2_64u),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_64s),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_32u),
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
return normTab[normType][depth];
|
||||
}
|
||||
typedef int (*NormFunc)(const uchar*, const uchar*, uchar*, int, int);
|
||||
typedef int (*NormDiffFunc)(const uchar*, const uchar*, const uchar*, uchar*, int, int);
|
||||
|
||||
static NormDiffFunc getNormDiffFunc(int normType, int depth)
|
||||
{
|
||||
static NormDiffFunc normDiffTab[3][CV_DEPTH_MAX] =
|
||||
{
|
||||
{
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_8u),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_8s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_16u),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_16s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_32s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_32f),
|
||||
(NormDiffFunc)normDiffInf_64f,
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_16f),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_16bf),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_8u), (NormDiffFunc)normDiffInf_8s,
|
||||
(NormDiffFunc)normDiffInf_16u, (NormDiffFunc)normDiffInf_16s,
|
||||
(NormDiffFunc)normDiffInf_32s,
|
||||
(NormDiffFunc)normDiffInf_32f, (NormDiffFunc)normDiffInf_64f,
|
||||
(NormDiffFunc)normDiffInf_16f, (NormDiffFunc)normDiffInf_16bf,
|
||||
(NormDiffFunc)normDiffInf_Bool,
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_64u),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_64s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffInf_32u),
|
||||
(NormDiffFunc)normDiffInf_64u, (NormDiffFunc)normDiffInf_64s,
|
||||
(NormDiffFunc)normDiffInf_32u,
|
||||
0
|
||||
},
|
||||
{
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_8u),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_8s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_16u),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_16s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_32s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_32f),
|
||||
(NormDiffFunc)normDiffL1_64f,
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_16f),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_16bf),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_8u), (NormDiffFunc)normDiffL1_8s,
|
||||
(NormDiffFunc)normDiffL1_16u, (NormDiffFunc)GET_OPTIMIZED(normDiffL1_16s),
|
||||
(NormDiffFunc)normDiffL1_32s,
|
||||
(NormDiffFunc)normDiffL1_32f, (NormDiffFunc)normDiffL1_64f,
|
||||
(NormDiffFunc)normDiffL1_16f, (NormDiffFunc)normDiffL1_16bf,
|
||||
(NormDiffFunc)normDiffL1_Bool,
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_64u),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_64s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL1_32u),
|
||||
(NormDiffFunc)normDiffL1_64u, (NormDiffFunc)normDiffL1_64s,
|
||||
(NormDiffFunc)normDiffL1_32u,
|
||||
0
|
||||
},
|
||||
{
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_8u),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_8s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_16u),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_16s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_32s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_32f),
|
||||
(NormDiffFunc)normDiffL2_64f,
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_16f),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_16bf),
|
||||
(NormDiffFunc)normDiffL2_8s,
|
||||
(NormDiffFunc)normDiffL2_16u, (NormDiffFunc)normDiffL2_16s,
|
||||
(NormDiffFunc)normDiffL2_32s,
|
||||
(NormDiffFunc)normDiffL2_32f, (NormDiffFunc)normDiffL2_64f,
|
||||
(NormDiffFunc)normDiffL2_16f, (NormDiffFunc)normDiffL2_16bf,
|
||||
(NormDiffFunc)normDiffL2_Bool,
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_64u),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_64s),
|
||||
(NormDiffFunc)GET_OPTIMIZED(normDiffL2_32u),
|
||||
(NormDiffFunc)normDiffL2_64u, (NormDiffFunc)normDiffL2_64s,
|
||||
(NormDiffFunc)normDiffL2_32u,
|
||||
0
|
||||
}
|
||||
};
|
||||
@@ -783,6 +592,11 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result)
|
||||
} // ipp_norm()
|
||||
#endif // HAVE_IPP
|
||||
|
||||
static NormFunc getNormFunc(int normType, int depth) {
|
||||
CV_INSTRUMENT_REGION();
|
||||
CV_CPU_DISPATCH(getNormFunc, (normType, depth), CV_CPU_DISPATCH_MODES_ALL);
|
||||
}
|
||||
|
||||
double norm( InputArray _src, int normType, InputArray _mask )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
@@ -817,6 +631,9 @@ double norm( InputArray _src, int normType, InputArray _mask )
|
||||
|
||||
CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_norm(src, normType, mask, _result), _result);
|
||||
|
||||
NormFunc func = getNormFunc(normType >> 1, depth);
|
||||
CV_Assert( func != 0 );
|
||||
|
||||
if( src.isContinuous() && mask.empty() )
|
||||
{
|
||||
size_t len = src.total()*cn;
|
||||
@@ -824,30 +641,18 @@ double norm( InputArray _src, int normType, InputArray _mask )
|
||||
{
|
||||
if( depth == CV_32F )
|
||||
{
|
||||
const float* data = src.ptr<float>();
|
||||
const uchar* data = src.ptr<const uchar>();
|
||||
|
||||
if( normType == NORM_L2 )
|
||||
if( normType == NORM_L2 || normType == NORM_L2SQR || normType == NORM_L1 )
|
||||
{
|
||||
double result = 0;
|
||||
GET_OPTIMIZED(normL2_32f)(data, 0, &result, (int)len, 1);
|
||||
return std::sqrt(result);
|
||||
}
|
||||
if( normType == NORM_L2SQR )
|
||||
{
|
||||
double result = 0;
|
||||
GET_OPTIMIZED(normL2_32f)(data, 0, &result, (int)len, 1);
|
||||
return result;
|
||||
}
|
||||
if( normType == NORM_L1 )
|
||||
{
|
||||
double result = 0;
|
||||
GET_OPTIMIZED(normL1_32f)(data, 0, &result, (int)len, 1);
|
||||
return result;
|
||||
func(data, 0, (uchar*)&result, (int)len, 1);
|
||||
return normType == NORM_L2 ? std::sqrt(result) : result;
|
||||
}
|
||||
if( normType == NORM_INF )
|
||||
{
|
||||
float result = 0;
|
||||
GET_OPTIMIZED(normInf_32f)(data, 0, &result, (int)len, 1);
|
||||
func(data, 0, (uchar*)&result, (int)len, 1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -857,7 +662,7 @@ double norm( InputArray _src, int normType, InputArray _mask )
|
||||
|
||||
if( normType == NORM_HAMMING )
|
||||
{
|
||||
return hal::normHamming(data, (int)len);
|
||||
return hal::normHamming(data, (int)len, 1);
|
||||
}
|
||||
|
||||
if( normType == NORM_HAMMING2 )
|
||||
@@ -894,9 +699,6 @@ double norm( InputArray _src, int normType, InputArray _mask )
|
||||
return result;
|
||||
}
|
||||
|
||||
NormFunc func = getNormFunc(normType >> 1, depth);
|
||||
CV_Assert( func != 0 );
|
||||
|
||||
const Mat* arrays[] = {&src, &mask, 0};
|
||||
uchar* ptrs[2] = {};
|
||||
union
|
||||
@@ -934,7 +736,7 @@ double norm( InputArray _src, int normType, InputArray _mask )
|
||||
for (int j = 0; j < total; j += blockSize)
|
||||
{
|
||||
int bsz = std::min(total - j, blockSize);
|
||||
func(ptrs[0], ptrs[1], &blocksum.i, bsz, cn);
|
||||
func(ptrs[0], ptrs[1], (uchar*)&blocksum, bsz, cn);
|
||||
count += bsz;
|
||||
if (count + blockSize >= blockSize0 || (i+1 >= it.nplanes && j+bsz >= total))
|
||||
{
|
||||
@@ -953,7 +755,7 @@ double norm( InputArray _src, int normType, InputArray _mask )
|
||||
// generic implementation
|
||||
for (size_t i = 0; i < it.nplanes; i++, ++it)
|
||||
{
|
||||
func(ptrs[0], ptrs[1], &result, (int)it.size, cn);
|
||||
func(ptrs[0], ptrs[1], (uchar*)&result, (int)it.size, cn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1418,7 +1220,7 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask
|
||||
for (int j = 0; j < total; j += blockSize)
|
||||
{
|
||||
int bsz = std::min(total - j, blockSize);
|
||||
func(ptrs[0], ptrs[1], ptrs[2], &blocksum.i, bsz, cn);
|
||||
func(ptrs[0], ptrs[1], ptrs[2], (uchar*)&blocksum, bsz, cn);
|
||||
count += bsz;
|
||||
if (count + blockSize >= blockSize0 || (i+1 >= it.nplanes && j+bsz >= total))
|
||||
{
|
||||
@@ -1438,7 +1240,7 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask
|
||||
// generic implementation
|
||||
for (size_t i = 0; i < it.nplanes; i++, ++it)
|
||||
{
|
||||
func(ptrs[0], ptrs[1], ptrs[2], &result, (int)it.size, cn);
|
||||
func(ptrs[0], ptrs[1], ptrs[2], (uchar*)&result, (int)it.size, cn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
// 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.
|
||||
//
|
||||
// Copytright (C) 2025, SpaceMIT Inc., all rights reserved.
|
||||
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
|
||||
namespace cv {
|
||||
|
||||
namespace {
|
||||
|
||||
// [TODO] Drop this until rvv has dedicated intrinsics for abs on integers.
|
||||
template<typename T, typename ST> inline ST __riscv_vabs(const T&);
|
||||
|
||||
template<> inline
|
||||
vuint8m1_t __riscv_vabs(const vint8m1_t& v) {
|
||||
const int vle8m1 = __riscv_vsetvlmax_e8m1();
|
||||
vint8m1_t mask = __riscv_vsra_vx_i8m1(v, 7, vle8m1);
|
||||
vint8m1_t v_xor = __riscv_vxor_vv_i8m1(v, mask, vle8m1);
|
||||
return __riscv_vreinterpret_v_i8m1_u8m1(
|
||||
__riscv_vsub_vv_i8m1(v_xor, mask, vle8m1)
|
||||
);
|
||||
}
|
||||
|
||||
template<> inline
|
||||
vuint16m1_t __riscv_vabs(const vint16m1_t& v) {
|
||||
const int vle16m1 = __riscv_vsetvlmax_e16m1();
|
||||
vint16m1_t mask = __riscv_vsra_vx_i16m1(v, 15, vle16m1);
|
||||
vint16m1_t v_xor = __riscv_vxor_vv_i16m1(v, mask, vle16m1);
|
||||
return __riscv_vreinterpret_v_i16m1_u16m1(
|
||||
__riscv_vsub_vv_i16m1(v_xor, mask, vle16m1)
|
||||
);
|
||||
}
|
||||
|
||||
template<> inline
|
||||
vuint32m1_t __riscv_vabs(const vint32m1_t& v) {
|
||||
const int vle32m1 = __riscv_vsetvlmax_e32m1();
|
||||
vint32m1_t mask = __riscv_vsra_vx_i32m1(v, 31, vle32m1);
|
||||
vint32m1_t v_xor = __riscv_vxor_vv_i32m1(v, mask, vle32m1);
|
||||
return __riscv_vreinterpret_v_i32m1_u32m1(
|
||||
__riscv_vsub_vv_i32m1(v_xor, mask, vle32m1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
|
||||
|
||||
template <typename T, typename ST> inline
|
||||
ST normInf_rvv(const T* src, int n, int& j);
|
||||
|
||||
template<> inline
|
||||
int normInf_rvv(const int* src, int n, int& j) {
|
||||
const int vle32m1 = __riscv_vsetvlmax_e32m1();
|
||||
vuint32m1_t r0 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
vuint32m1_t r1 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
for (; j <= n - 2 * vle32m1; j += 2 * vle32m1) {
|
||||
vuint32m1_t v0 = __riscv_vabs<vint32m1_t, vuint32m1_t>(__riscv_vle32_v_i32m1(src + j, vle32m1));
|
||||
r0 = __riscv_vmaxu(r0, v0, vle32m1);
|
||||
|
||||
vuint32m1_t v1 = __riscv_vabs<vint32m1_t, vuint32m1_t>(__riscv_vle32_v_i32m1(src + j + vle32m1, vle32m1));
|
||||
r1 = __riscv_vmaxu(r1, v1, vle32m1);
|
||||
}
|
||||
r0 = __riscv_vmaxu(r0, r1, vle32m1);
|
||||
return (int)__riscv_vmv_x(__riscv_vredmaxu(r0, __riscv_vmv_v_x_u32m1(0, vle32m1), vle32m1));
|
||||
}
|
||||
|
||||
template <typename T, typename ST> inline
|
||||
ST normL1_rvv(const T* src, int n, int& j);
|
||||
|
||||
template<> inline
|
||||
int normL1_rvv(const schar* src, int n, int& j) {
|
||||
const int vle8m1 = __riscv_vsetvlmax_e8m1();
|
||||
const int vle16m1 = __riscv_vsetvlmax_e16m1();
|
||||
const int vle32m1 = __riscv_vsetvlmax_e32m1();
|
||||
vuint32m1_t r0 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
vuint32m1_t r1 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
vuint16m1_t zero = __riscv_vmv_v_x_u16m1(0, vle16m1);
|
||||
for (; j <= n - 2 * vle8m1; j += 2 * vle8m1) {
|
||||
vuint8m1_t v0 = __riscv_vabs<vint8m1_t, vuint8m1_t>(__riscv_vle8_v_i8m1(src + j, vle8m1));
|
||||
vuint16m1_t u0 = __riscv_vwredsumu_tu(zero, v0, zero, vle8m1);
|
||||
r0 = __riscv_vwredsumu(u0, r0, vle16m1);
|
||||
|
||||
vuint8m1_t v1 = __riscv_vabs<vint8m1_t, vuint8m1_t>(__riscv_vle8_v_i8m1(src + j + vle8m1, vle8m1));
|
||||
vuint16m1_t u1 = __riscv_vwredsumu_tu(zero, v1, zero, vle8m1);
|
||||
r1 = __riscv_vwredsumu(u1, r1, vle16m1);
|
||||
}
|
||||
return (int)__riscv_vmv_x(__riscv_vadd(r0, r1, vle32m1));
|
||||
}
|
||||
|
||||
template<> inline
|
||||
int normL1_rvv(const ushort* src, int n, int& j) {
|
||||
const int vle16m1 = __riscv_vsetvlmax_e16m1();
|
||||
const int vle32m1 = __riscv_vsetvlmax_e32m1();
|
||||
vuint32m1_t r0 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
vuint32m1_t r1 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
for (; j <= n - 2 * vle16m1; j += 2 * vle16m1) {
|
||||
vuint16m1_t v0 = __riscv_vle16_v_u16m1(src + j, vle16m1);
|
||||
r0 = __riscv_vwredsumu(v0, r0, vle16m1);
|
||||
|
||||
vuint16m1_t v1 = __riscv_vle16_v_u16m1(src + j + vle16m1, vle16m1);
|
||||
r1 = __riscv_vwredsumu(v1, r1, vle16m1);
|
||||
}
|
||||
return (int)__riscv_vmv_x(__riscv_vadd(r0, r1, vle32m1));
|
||||
}
|
||||
|
||||
template<> inline
|
||||
int normL1_rvv(const short* src, int n, int& j) {
|
||||
const int vle16m1 = __riscv_vsetvlmax_e16m1();
|
||||
const int vle32m1 = __riscv_vsetvlmax_e32m1();
|
||||
vuint32m1_t r0 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
vuint32m1_t r1 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
for (; j<= n - 2 * vle16m1; j += 2 * vle16m1) {
|
||||
vuint16m1_t v0 = __riscv_vabs<vint16m1_t, vuint16m1_t>(__riscv_vle16_v_i16m1(src + j, vle16m1));
|
||||
r0 = __riscv_vwredsumu(v0, r0, vle16m1);
|
||||
|
||||
vuint16m1_t v1 = __riscv_vabs<vint16m1_t, vuint16m1_t>(__riscv_vle16_v_i16m1(src + j + vle16m1, vle16m1));
|
||||
r1 = __riscv_vwredsumu(v1, r1, vle16m1);
|
||||
}
|
||||
return (int)__riscv_vmv_x(__riscv_vadd(r0, r1, vle32m1));
|
||||
}
|
||||
|
||||
template<> inline
|
||||
double normL1_rvv(const double* src, int n, int& j) {
|
||||
const int vle64m1 = __riscv_vsetvlmax_e64m1();
|
||||
vfloat64m1_t r0 = __riscv_vfmv_v_f_f64m1(0.f, vle64m1);
|
||||
vfloat64m1_t r1 = __riscv_vfmv_v_f_f64m1(0.f, vle64m1);
|
||||
for (; j <= n - 2 * vle64m1; j += 2 * vle64m1) {
|
||||
vfloat64m1_t v0 = __riscv_vle64_v_f64m1(src + j, vle64m1);
|
||||
v0 = __riscv_vfabs(v0, vle64m1);
|
||||
r0 = __riscv_vfadd(r0, v0, vle64m1);
|
||||
|
||||
vfloat64m1_t v1 = __riscv_vle64_v_f64m1(src + j + vle64m1, vle64m1);
|
||||
v1 = __riscv_vfabs(v1, vle64m1);
|
||||
r1 = __riscv_vfadd(r1, v1, vle64m1);
|
||||
}
|
||||
r0 = __riscv_vfadd(r0, r1, vle64m1);
|
||||
return __riscv_vfmv_f(__riscv_vfredusum(r0, __riscv_vfmv_v_f_f64m1(0.f, vle64m1), vle64m1));
|
||||
}
|
||||
|
||||
template <typename T, typename ST> inline
|
||||
ST normL2_rvv(const T* src, int n, int& j);
|
||||
|
||||
template<> inline
|
||||
int normL2_rvv(const uchar* src, int n, int& j) {
|
||||
const int vle8m1 = __riscv_vsetvlmax_e8m1();
|
||||
const int vle16m1 = __riscv_vsetvlmax_e16m1();
|
||||
const int vle32m1 = __riscv_vsetvlmax_e32m1();
|
||||
vuint32m1_t r0 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
vuint32m1_t r1 = __riscv_vmv_v_x_u32m1(0, vle32m1);
|
||||
for (; j <= n - 2 * vle8m1; j += 2 * vle8m1) {
|
||||
vuint8m1_t v0 = __riscv_vle8_v_u8m1(src + j, vle8m1);
|
||||
vuint16m2_t u0 = __riscv_vwmulu(v0, v0, vle8m1);
|
||||
r0 = __riscv_vwredsumu(u0, r0, vle16m1 * 2);
|
||||
|
||||
vuint8m1_t v1 = __riscv_vle8_v_u8m1(src + j + vle8m1, vle8m1);
|
||||
vuint16m2_t u1 = __riscv_vwmulu(v1, v1, vle8m1);
|
||||
r1 = __riscv_vwredsumu(u1, r1, vle16m1 * 2);
|
||||
}
|
||||
return (int)__riscv_vmv_x(__riscv_vadd(r0, r1, vle32m1));
|
||||
}
|
||||
|
||||
template<> inline
|
||||
int normL2_rvv(const schar* src, int n, int& j) {
|
||||
const int vle8m1 = __riscv_vsetvlmax_e8m1();
|
||||
const int vle16m1 = __riscv_vsetvlmax_e16m1();
|
||||
const int vle32m1 = __riscv_vsetvlmax_e32m1();
|
||||
vint32m1_t r0 = __riscv_vmv_v_x_i32m1(0, vle32m1);
|
||||
vint32m1_t r1 = __riscv_vmv_v_x_i32m1(0, vle32m1);
|
||||
for (; j <= n - 2 * vle8m1; j += 2 * vle8m1) {
|
||||
vint8m1_t v0 = __riscv_vle8_v_i8m1(src + j, vle8m1);
|
||||
vint16m2_t u0 = __riscv_vwmul(v0, v0, vle8m1);
|
||||
r0 = __riscv_vwredsum(u0, r0, vle16m1 * 2);
|
||||
|
||||
vint8m1_t v1 = __riscv_vle8_v_i8m1(src + j + vle8m1, vle8m1);
|
||||
vint16m2_t u1 = __riscv_vwmul(v1, v1, vle8m1);
|
||||
r1 = __riscv_vwredsum(u1, r1, vle16m1 * 2);
|
||||
}
|
||||
return __riscv_vmv_x(__riscv_vadd(r0, r1, vle32m1));
|
||||
}
|
||||
|
||||
template<> inline
|
||||
double normL2_rvv(const double* src, int n, int& j) {
|
||||
const int vle64m1 = __riscv_vsetvlmax_e64m1();
|
||||
vfloat64m1_t r0 = __riscv_vfmv_v_f_f64m1(0.f, vle64m1);
|
||||
vfloat64m1_t r1 = __riscv_vfmv_v_f_f64m1(0.f, vle64m1);
|
||||
for (; j <= n - 2 * vle64m1; j += 2 * vle64m1) {
|
||||
vfloat64m1_t v0 = __riscv_vle64_v_f64m1(src + j, vle64m1);
|
||||
r0 = __riscv_vfmacc(r0, v0, v0, vle64m1);
|
||||
|
||||
vfloat64m1_t v1 = __riscv_vle64_v_f64m1(src + j + vle64m1, vle64m1);
|
||||
r1 = __riscv_vfmacc(r1, v1, v1, vle64m1);
|
||||
}
|
||||
r0 = __riscv_vfadd(r0, r1, vle64m1);
|
||||
return __riscv_vfmv_f(__riscv_vfredusum(r0, __riscv_vfmv_v_f_f64m1(0.f, vle64m1), vle64m1));
|
||||
}
|
||||
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_END
|
||||
|
||||
} // cv::
|
||||
@@ -0,0 +1,779 @@
|
||||
// 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
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#if CV_RVV
|
||||
#include "norm.rvv1p0.hpp"
|
||||
#endif
|
||||
|
||||
namespace cv {
|
||||
|
||||
using NormFunc = int (*)(const uchar*, const uchar*, uchar*, int, int);
|
||||
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
|
||||
|
||||
NormFunc getNormFunc(int normType, int depth);
|
||||
|
||||
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
|
||||
|
||||
template <typename T, typename ST>
|
||||
struct NormInf_SIMD {
|
||||
inline ST operator() (const T* src, int n) const {
|
||||
ST s = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
s = std::max(s, (ST)cv_abs(src[i]));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename ST>
|
||||
struct NormL1_SIMD {
|
||||
inline ST operator() (const T* src, int n) const {
|
||||
ST s = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
s += cv_abs(src[i]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename ST>
|
||||
struct NormL2_SIMD {
|
||||
inline ST operator() (const T* src, int n) const {
|
||||
ST s = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
ST v = src[i];
|
||||
s += v * v;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
|
||||
template<>
|
||||
struct NormInf_SIMD<uchar, int> {
|
||||
int operator() (const uchar* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
v_uint8 r0 = vx_setzero_u8(), r1 = vx_setzero_u8();
|
||||
v_uint8 r2 = vx_setzero_u8(), r3 = vx_setzero_u8();
|
||||
for (; j <= n - 4 * VTraits<v_uint8>::vlanes(); j += 4 * VTraits<v_uint8>::vlanes()) {
|
||||
r0 = v_max(r0, vx_load(src + j ));
|
||||
r1 = v_max(r1, vx_load(src + j + VTraits<v_uint8>::vlanes()));
|
||||
r2 = v_max(r2, vx_load(src + j + 2 * VTraits<v_uint8>::vlanes()));
|
||||
r3 = v_max(r3, vx_load(src + j + 3 * VTraits<v_uint8>::vlanes()));
|
||||
}
|
||||
r0 = v_max(r0, v_max(r1, v_max(r2, r3)));
|
||||
for (; j < n; j++) {
|
||||
s = std::max(s, (int)src[j]);
|
||||
}
|
||||
return std::max(s, (int)v_reduce_max(r0));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormInf_SIMD<schar, int> {
|
||||
int operator() (const schar* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
v_uint8 r0 = vx_setzero_u8(), r1 = vx_setzero_u8();
|
||||
v_uint8 r2 = vx_setzero_u8(), r3 = vx_setzero_u8();
|
||||
for (; j <= n - 4 * VTraits<v_int8>::vlanes(); j += 4 * VTraits<v_int8>::vlanes()) {
|
||||
r0 = v_max(r0, v_abs(vx_load(src + j )));
|
||||
r1 = v_max(r1, v_abs(vx_load(src + j + VTraits<v_int8>::vlanes())));
|
||||
r2 = v_max(r2, v_abs(vx_load(src + j + 2 * VTraits<v_int8>::vlanes())));
|
||||
r3 = v_max(r3, v_abs(vx_load(src + j + 3 * VTraits<v_int8>::vlanes())));
|
||||
}
|
||||
r0 = v_max(r0, v_max(r1, v_max(r2, r3)));
|
||||
for (; j < n; j++) {
|
||||
s = std::max(s, cv_abs(src[j]));
|
||||
}
|
||||
return std::max(s, saturate_cast<int>(v_reduce_max(r0)));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormInf_SIMD<ushort, int> {
|
||||
int operator() (const ushort* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
v_uint16 d0 = vx_setzero_u16(), d1 = vx_setzero_u16();
|
||||
v_uint16 d2 = vx_setzero_u16(), d3 = vx_setzero_u16();
|
||||
for (; j <= n - 4 * VTraits<v_uint16>::vlanes(); j += 4 * VTraits<v_uint16>::vlanes()) {
|
||||
d0 = v_max(d0, vx_load(src + j ));
|
||||
d1 = v_max(d1, vx_load(src + j + VTraits<v_uint16>::vlanes()));
|
||||
d2 = v_max(d2, vx_load(src + j + 2 * VTraits<v_uint16>::vlanes()));
|
||||
d3 = v_max(d3, vx_load(src + j + 3 * VTraits<v_uint16>::vlanes()));
|
||||
}
|
||||
d0 = v_max(d0, v_max(d1, v_max(d2, d3)));
|
||||
for (; j < n; j++) {
|
||||
s = std::max(s, (int)src[j]);
|
||||
}
|
||||
return std::max(s, (int)v_reduce_max(d0));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormInf_SIMD<short, int> {
|
||||
int operator() (const short* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
v_uint16 d0 = vx_setzero_u16(), d1 = vx_setzero_u16();
|
||||
v_uint16 d2 = vx_setzero_u16(), d3 = vx_setzero_u16();
|
||||
for (; j <= n - 4 * VTraits<v_int16>::vlanes(); j += 4 * VTraits<v_int16>::vlanes()) {
|
||||
d0 = v_max(d0, v_abs(vx_load(src + j )));
|
||||
d1 = v_max(d1, v_abs(vx_load(src + j + VTraits<v_int16>::vlanes())));
|
||||
d2 = v_max(d2, v_abs(vx_load(src + j + 2 * VTraits<v_int16>::vlanes())));
|
||||
d3 = v_max(d3, v_abs(vx_load(src + j + 3 * VTraits<v_int16>::vlanes())));
|
||||
}
|
||||
d0 = v_max(d0, v_max(d1, v_max(d2, d3)));
|
||||
for (; j < n; j++) {
|
||||
s = std::max(s, saturate_cast<int>(cv_abs(src[j])));
|
||||
}
|
||||
return std::max(s, saturate_cast<int>(v_reduce_max(d0)));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormInf_SIMD<int, int> {
|
||||
int operator() (const int* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
#if CV_RVV
|
||||
s = normInf_rvv<int, int>(src, n, j);
|
||||
#else
|
||||
v_uint32 r0 = vx_setzero_u32(), r1 = vx_setzero_u32();
|
||||
v_uint32 r2 = vx_setzero_u32(), r3 = vx_setzero_u32();
|
||||
for (; j <= n - 4 * VTraits<v_int32>::vlanes(); j += 4 * VTraits<v_int32>::vlanes()) {
|
||||
r0 = v_max(r0, v_abs(vx_load(src + j )));
|
||||
r1 = v_max(r1, v_abs(vx_load(src + j + VTraits<v_int32>::vlanes())));
|
||||
r2 = v_max(r2, v_abs(vx_load(src + j + 2 * VTraits<v_int32>::vlanes())));
|
||||
r3 = v_max(r3, v_abs(vx_load(src + j + 3 * VTraits<v_int32>::vlanes())));
|
||||
}
|
||||
r0 = v_max(r0, v_max(r1, v_max(r2, r3)));
|
||||
s = std::max(s, saturate_cast<int>(v_reduce_max(r0)));
|
||||
#endif
|
||||
for (; j < n; j++) {
|
||||
s = std::max(s, std::abs(src[j]));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormInf_SIMD<float, float> {
|
||||
float operator() (const float* src, int n) const {
|
||||
int j = 0;
|
||||
float s = 0.f;
|
||||
v_float32 r0 = vx_setzero_f32(), r1 = vx_setzero_f32();
|
||||
v_float32 r2 = vx_setzero_f32(), r3 = vx_setzero_f32();
|
||||
for (; j <= n - 4 * VTraits<v_float32>::vlanes(); j += 4 * VTraits<v_float32>::vlanes()) {
|
||||
r0 = v_max(r0, v_abs(vx_load(src + j )));
|
||||
r1 = v_max(r1, v_abs(vx_load(src + j + VTraits<v_float32>::vlanes())));
|
||||
r2 = v_max(r2, v_abs(vx_load(src + j + 2 * VTraits<v_float32>::vlanes())));
|
||||
r3 = v_max(r3, v_abs(vx_load(src + j + 3 * VTraits<v_float32>::vlanes())));
|
||||
}
|
||||
r0 = v_max(r0, v_max(r1, v_max(r2, r3)));
|
||||
for (; j < n; j++) {
|
||||
s = std::max(s, cv_abs(src[j]));
|
||||
}
|
||||
return std::max(s, v_reduce_max(r0));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL1_SIMD<uchar, int> {
|
||||
int operator() (const uchar* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
v_uint32 r0 = vx_setzero_u32(), r1 = vx_setzero_u32();
|
||||
v_uint8 one = vx_setall_u8(1);
|
||||
for (; j<= n - 2 * VTraits<v_uint8>::vlanes(); j += 2 * VTraits<v_uint8>::vlanes()) {
|
||||
v_uint8 v0 = vx_load(src + j);
|
||||
r0 = v_dotprod_expand_fast(v0, one, r0);
|
||||
|
||||
v_uint8 v1 = vx_load(src + j + VTraits<v_uint8>::vlanes());
|
||||
r1 = v_dotprod_expand_fast(v1, one, r1);
|
||||
}
|
||||
s += v_reduce_sum(v_add(r0, r1));
|
||||
for (; j < n; j++) {
|
||||
s += src[j];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL1_SIMD<schar, int> {
|
||||
int operator() (const schar* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
#if CV_RVV
|
||||
s = normL1_rvv<schar, int>(src, n, j);
|
||||
#else
|
||||
v_uint32 r0 = vx_setzero_u32(), r1 = vx_setzero_u32();
|
||||
v_uint8 one = vx_setall_u8(1);
|
||||
for (; j<= n - 2 * VTraits<v_int8>::vlanes(); j += 2 * VTraits<v_int8>::vlanes()) {
|
||||
v_uint8 v0 = v_abs(vx_load(src + j));
|
||||
r0 = v_dotprod_expand_fast(v0, one, r0);
|
||||
|
||||
v_uint8 v1 = v_abs(vx_load(src + j + VTraits<v_int8>::vlanes()));
|
||||
r1 = v_dotprod_expand_fast(v1, one, r1);
|
||||
}
|
||||
s += v_reduce_sum(v_add(r0, r1));
|
||||
#endif
|
||||
for (; j < n; j++) {
|
||||
s += saturate_cast<int>(cv_abs(src[j]));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL1_SIMD<ushort, int> {
|
||||
int operator() (const ushort* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
#if CV_RVV
|
||||
s = normL1_rvv<ushort, int>(src, n, j);
|
||||
#else
|
||||
v_uint32 r00 = vx_setzero_u32(), r01 = vx_setzero_u32();
|
||||
v_uint32 r10 = vx_setzero_u32(), r11 = vx_setzero_u32();
|
||||
for (; j<= n - 2 * VTraits<v_uint16>::vlanes(); j += 2 * VTraits<v_uint16>::vlanes()) {
|
||||
v_uint16 v0 = vx_load(src + j);
|
||||
v_uint32 v00, v01;
|
||||
v_expand(v0, v00, v01);
|
||||
r00 = v_add(r00, v00);
|
||||
r01 = v_add(r01, v01);
|
||||
|
||||
v_uint16 v1 = vx_load(src + j + VTraits<v_uint16>::vlanes());
|
||||
v_uint32 v10, v11;
|
||||
v_expand(v1, v10, v11);
|
||||
r10 = v_add(r10, v10);
|
||||
r11 = v_add(r11, v11);
|
||||
}
|
||||
s += (int)v_reduce_sum(v_add(v_add(v_add(r00, r01), r10), r11));
|
||||
#endif
|
||||
for (; j < n; j++) {
|
||||
s += src[j];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL1_SIMD<short, int> {
|
||||
int operator() (const short* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
#if CV_RVV
|
||||
s = normL1_rvv<short, int>(src, n, j);
|
||||
#else
|
||||
v_uint32 r00 = vx_setzero_u32(), r01 = vx_setzero_u32();
|
||||
v_uint32 r10 = vx_setzero_u32(), r11 = vx_setzero_u32();
|
||||
for (; j<= n - 2 * VTraits<v_int16>::vlanes(); j += 2 * VTraits<v_int16>::vlanes()) {
|
||||
v_uint16 v0 = v_abs(vx_load(src + j));
|
||||
v_uint32 v00, v01;
|
||||
v_expand(v0, v00, v01);
|
||||
r00 = v_add(r00, v00);
|
||||
r01 = v_add(r01, v01);
|
||||
|
||||
v_uint16 v1 = v_abs(vx_load(src + j + VTraits<v_int16>::vlanes()));
|
||||
v_uint32 v10, v11;
|
||||
v_expand(v1, v10, v11);
|
||||
r10 = v_add(r10, v10);
|
||||
r11 = v_add(r11, v11);
|
||||
}
|
||||
s += (int)v_reduce_sum(v_add(v_add(v_add(r00, r01), r10), r11));
|
||||
#endif
|
||||
for (; j < n; j++) {
|
||||
s += saturate_cast<int>(cv_abs(src[j]));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL2_SIMD<uchar, int> {
|
||||
int operator() (const uchar* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
#if CV_RVV
|
||||
s = normL2_rvv<uchar, int>(src, n, j);
|
||||
#else
|
||||
v_uint32 r0 = vx_setzero_u32(), r1 = vx_setzero_u32();
|
||||
for (; j <= n - 2 * VTraits<v_uint8>::vlanes(); j += 2 * VTraits<v_uint8>::vlanes()) {
|
||||
v_uint8 v0 = vx_load(src + j);
|
||||
r0 = v_dotprod_expand_fast(v0, v0, r0);
|
||||
|
||||
v_uint8 v1 = vx_load(src + j + VTraits<v_uint8>::vlanes());
|
||||
r1 = v_dotprod_expand_fast(v1, v1, r1);
|
||||
}
|
||||
s += v_reduce_sum(v_add(r0, r1));
|
||||
#endif
|
||||
for (; j < n; j++) {
|
||||
int v = saturate_cast<int>(src[j]);
|
||||
s += v * v;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL2_SIMD<schar, int> {
|
||||
int operator() (const schar* src, int n) const {
|
||||
int j = 0;
|
||||
int s = 0;
|
||||
#if CV_RVV
|
||||
s = normL2_rvv<schar, int>(src, n, j);
|
||||
#else
|
||||
v_int32 r0 = vx_setzero_s32(), r1 = vx_setzero_s32();
|
||||
for (; j <= n - 2 * VTraits<v_int8>::vlanes(); j += 2 * VTraits<v_int8>::vlanes()) {
|
||||
v_int8 v0 = vx_load(src + j);
|
||||
r0 = v_dotprod_expand_fast(v0, v0, r0);
|
||||
v_int8 v1 = vx_load(src + j + VTraits<v_int8>::vlanes());
|
||||
r1 = v_dotprod_expand_fast(v1, v1, r1);
|
||||
}
|
||||
s += v_reduce_sum(v_add(r0, r1));
|
||||
#endif
|
||||
for (; j < n; j++) {
|
||||
int v = saturate_cast<int>(src[j]);
|
||||
s += v * v;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if (CV_SIMD_64F || CV_SIMD_SCALABLE_64F)
|
||||
|
||||
template<>
|
||||
struct NormInf_SIMD<double, double> {
|
||||
double operator() (const double* src, int n) const {
|
||||
int j = 0;
|
||||
double s = 0.f;
|
||||
v_float64 r0 = vx_setzero_f64(), r1 = vx_setzero_f64();
|
||||
v_float64 r2 = vx_setzero_f64(), r3 = vx_setzero_f64();
|
||||
for (; j <= n - 4 * VTraits<v_float64>::vlanes(); j += 4 * VTraits<v_float64>::vlanes()) {
|
||||
r0 = v_max(r0, v_abs(vx_load(src + j )));
|
||||
r1 = v_max(r1, v_abs(vx_load(src + j + VTraits<v_float64>::vlanes())));
|
||||
r2 = v_max(r2, v_abs(vx_load(src + j + 2 * VTraits<v_float64>::vlanes())));
|
||||
r3 = v_max(r3, v_abs(vx_load(src + j + 3 * VTraits<v_float64>::vlanes())));
|
||||
}
|
||||
r0 = v_max(r0, v_max(r1, v_max(r2, r3)));
|
||||
for (; j < n; j++) {
|
||||
s = std::max(s, cv_abs(src[j]));
|
||||
}
|
||||
// [TODO]: use v_reduce_max when it supports float64
|
||||
double t[VTraits<v_float64>::max_nlanes];
|
||||
vx_store(t, r0);
|
||||
for (int i = 0; i < VTraits<v_float64>::vlanes(); i++) {
|
||||
s = std::max(s, cv_abs(t[i]));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL1_SIMD<int, double> {
|
||||
double operator() (const int* src, int n) const {
|
||||
int j = 0;
|
||||
double s = 0.f;
|
||||
v_float64 r00 = vx_setzero_f64(), r01 = vx_setzero_f64();
|
||||
v_float64 r10 = vx_setzero_f64(), r11 = vx_setzero_f64();
|
||||
for (; j <= n - 2 * VTraits<v_int32>::vlanes(); j += 2 * VTraits<v_int32>::vlanes()) {
|
||||
v_float32 v0 = v_abs(v_cvt_f32(vx_load(src + j))), v1 = v_abs(v_cvt_f32(vx_load(src + j + VTraits<v_int32>::vlanes())));
|
||||
r00 = v_add(r00, v_cvt_f64(v0)); r01 = v_add(r01, v_cvt_f64_high(v0));
|
||||
r10 = v_add(r10, v_cvt_f64(v1)); r11 = v_add(r11, v_cvt_f64_high(v1));
|
||||
}
|
||||
s += v_reduce_sum(v_add(v_add(v_add(r00, r01), r10), r11));
|
||||
for (; j < n; j++) {
|
||||
s += cv_abs(src[j]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL1_SIMD<float, double> {
|
||||
double operator() (const float* src, int n) const {
|
||||
int j = 0;
|
||||
double s = 0.f;
|
||||
v_float64 r00 = vx_setzero_f64(), r01 = vx_setzero_f64();
|
||||
v_float64 r10 = vx_setzero_f64(), r11 = vx_setzero_f64();
|
||||
v_float64 r20 = vx_setzero_f64(), r21 = vx_setzero_f64();
|
||||
v_float64 r30 = vx_setzero_f64(), r31 = vx_setzero_f64();
|
||||
for (; j <= n - 4 * VTraits<v_float32>::vlanes(); j += 4 * VTraits<v_float32>::vlanes()) {
|
||||
v_float32 v0 = v_abs(vx_load(src + j)), v1 = v_abs(vx_load(src + j + VTraits<v_float32>::vlanes()));
|
||||
r00 = v_add(r00, v_cvt_f64(v0)); r01 = v_add(r01, v_cvt_f64_high(v0));
|
||||
r10 = v_add(r10, v_cvt_f64(v1)); r11 = v_add(r11, v_cvt_f64_high(v1));
|
||||
|
||||
v_float32 v2 = v_abs(vx_load(src + j + 2 * VTraits<v_float32>::vlanes())), v3 = v_abs(vx_load(src + j + 3 * VTraits<v_float32>::vlanes()));
|
||||
r20 = v_add(r20, v_cvt_f64(v2)); r21 = v_add(r21, v_cvt_f64_high(v2));
|
||||
r30 = v_add(r30, v_cvt_f64(v3)); r31 = v_add(r31, v_cvt_f64_high(v3));
|
||||
}
|
||||
s += v_reduce_sum(v_add(v_add(v_add(r00, r01), r10), r11));
|
||||
s += v_reduce_sum(v_add(v_add(v_add(r20, r21), r30), r31));
|
||||
for (; j < n; j++) {
|
||||
s += cv_abs(src[j]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL1_SIMD<double, double> {
|
||||
double operator() (const double* src, int n) const {
|
||||
int j = 0;
|
||||
double s = 0.f;
|
||||
#if CV_RVV // This is introduced to workaround the accuracy issue on ci
|
||||
s = normL1_rvv<double, double>(src, n, j);
|
||||
#else
|
||||
v_float64 r00 = vx_setzero_f64(), r01 = vx_setzero_f64();
|
||||
v_float64 r10 = vx_setzero_f64(), r11 = vx_setzero_f64();
|
||||
for (; j <= n - 4 * VTraits<v_float64>::vlanes(); j += 4 * VTraits<v_float64>::vlanes()) {
|
||||
r00 = v_add(r00, v_abs(vx_load(src + j )));
|
||||
r01 = v_add(r01, v_abs(vx_load(src + j + VTraits<v_float64>::vlanes())));
|
||||
r10 = v_add(r10, v_abs(vx_load(src + j + 2 * VTraits<v_float64>::vlanes())));
|
||||
r11 = v_add(r11, v_abs(vx_load(src + j + 3 * VTraits<v_float64>::vlanes())));
|
||||
}
|
||||
s += v_reduce_sum(v_add(v_add(v_add(r00, r01), r10), r11));
|
||||
#endif
|
||||
for (; j < n; j++) {
|
||||
s += cv_abs(src[j]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL2_SIMD<ushort, double> {
|
||||
double operator() (const ushort* src, int n) const {
|
||||
int j = 0;
|
||||
double s = 0.f;
|
||||
v_float64 r0 = vx_setzero_f64(), r1 = vx_setzero_f64();
|
||||
for (; j <= n - 2 * VTraits<v_uint16>::vlanes(); j += 2 * VTraits<v_uint16>::vlanes()) {
|
||||
v_uint16 v0 = vx_load(src + j);
|
||||
v_uint64 u0 = v_dotprod_expand_fast(v0, v0);
|
||||
r0 = v_add(r0, v_cvt_f64(v_reinterpret_as_s64(u0)));
|
||||
|
||||
v_uint16 v1 = vx_load(src + j + VTraits<v_uint16>::vlanes());
|
||||
v_uint64 u1 = v_dotprod_expand_fast(v1, v1);
|
||||
r1 = v_add(r1, v_cvt_f64(v_reinterpret_as_s64(u1)));
|
||||
}
|
||||
s += v_reduce_sum(v_add(r0, r1));
|
||||
for (; j < n; j++) {
|
||||
double v = saturate_cast<double>(src[j]);
|
||||
s += v * v;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL2_SIMD<short, double> {
|
||||
double operator() (const short* src, int n) const {
|
||||
int j = 0;
|
||||
double s = 0.f;
|
||||
v_float64 r0 = vx_setzero_f64(), r1 = vx_setzero_f64();
|
||||
for (; j <= n - 2 * VTraits<v_int16>::vlanes(); j += 2 * VTraits<v_int16>::vlanes()) {
|
||||
v_int16 v0 = vx_load(src + j);
|
||||
r0 = v_add(r0, v_cvt_f64(v_dotprod_expand_fast(v0, v0)));
|
||||
|
||||
v_int16 v1 = vx_load(src + j + VTraits<v_int16>::vlanes());
|
||||
r1 = v_add(r1, v_cvt_f64(v_dotprod_expand_fast(v1, v1)));
|
||||
}
|
||||
s += v_reduce_sum(v_add(r0, r1));
|
||||
for (; j < n; j++) {
|
||||
double v = saturate_cast<double>(src[j]);
|
||||
s += v * v;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL2_SIMD<int, double> {
|
||||
double operator() (const int* src, int n) const {
|
||||
int j = 0;
|
||||
double s = 0.f;
|
||||
v_float64 r0 = vx_setzero_f64(), r1 = vx_setzero_f64();
|
||||
for (; j <= n - 2 * VTraits<v_int32>::vlanes(); j += 2 * VTraits<v_int32>::vlanes()) {
|
||||
v_int32 v0 = vx_load(src + j);
|
||||
r0 = v_dotprod_expand_fast(v0, v0, r0);
|
||||
|
||||
v_int32 v1 = vx_load(src + j + VTraits<v_int32>::vlanes());
|
||||
r1 = v_dotprod_expand_fast(v1, v1, r1);
|
||||
}
|
||||
s += v_reduce_sum(v_add(r0, r1));
|
||||
for (; j < n; j++) {
|
||||
double v = src[j];
|
||||
s += v * v;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL2_SIMD<float, double> {
|
||||
double operator() (const float* src, int n) const {
|
||||
int j = 0;
|
||||
double s = 0.f;
|
||||
v_float64 r00 = vx_setzero_f64(), r01 = vx_setzero_f64();
|
||||
v_float64 r10 = vx_setzero_f64(), r11 = vx_setzero_f64();
|
||||
for (; j <= n - 2 * VTraits<v_float32>::vlanes(); j += 2 * VTraits<v_float32>::vlanes()) {
|
||||
v_float32 v0 = vx_load(src + j), v1 = vx_load(src + j + VTraits<v_float32>::vlanes());
|
||||
v_float64 v00 = v_cvt_f64(v0), v01 = v_cvt_f64_high(v0);
|
||||
v_float64 v10 = v_cvt_f64(v1), v11 = v_cvt_f64_high(v1);
|
||||
r00 = v_fma(v00, v00, r00); r01 = v_fma(v01, v01, r01);
|
||||
r10 = v_fma(v10, v10, r10); r11 = v_fma(v11, v11, r11);
|
||||
}
|
||||
s += v_reduce_sum(v_add(v_add(v_add(r00, r01), r10), r11));
|
||||
for (; j < n; j++) {
|
||||
double v = src[j];
|
||||
s += v * v;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct NormL2_SIMD<double, double> {
|
||||
double operator() (const double* src, int n) const {
|
||||
int j = 0;
|
||||
double s = 0.f;
|
||||
#if CV_RVV // This is introduced to workaround the accuracy issue on ci
|
||||
s = normL2_rvv<double, double>(src, n, j);
|
||||
#else
|
||||
v_float64 r00 = vx_setzero_f64(), r01 = vx_setzero_f64();
|
||||
v_float64 r10 = vx_setzero_f64(), r11 = vx_setzero_f64();
|
||||
for (; j <= n - 4 * VTraits<v_float64>::vlanes(); j += 4 * VTraits<v_float64>::vlanes()) {
|
||||
v_float64 v00 = vx_load(src + j );
|
||||
v_float64 v01 = vx_load(src + j + VTraits<v_float64>::vlanes());
|
||||
v_float64 v10 = vx_load(src + j + 2 * VTraits<v_float64>::vlanes());
|
||||
v_float64 v11 = vx_load(src + j + 3 * VTraits<v_float64>::vlanes());
|
||||
r00 = v_fma(v00, v00, r00); r01 = v_fma(v01, v01, r01);
|
||||
r10 = v_fma(v10, v10, r10); r11 = v_fma(v11, v11, r11);
|
||||
}
|
||||
s += v_reduce_sum(v_add(v_add(v_add(r00, r01), r10), r11));
|
||||
#endif
|
||||
for (; j < n; j++) {
|
||||
double v = src[j];
|
||||
s += v * v;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T, typename ST> int
|
||||
normInf_(const T* src, const uchar* mask, ST* _result, int len, int cn)
|
||||
{
|
||||
ST result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
result = std::max(result, normInf<T, ST>(src, len*cn));
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
result = std::max(result, (ST)cv_abs(src[k]));
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename ST> int
|
||||
normL1_(const T* src, const uchar* mask, ST* _result, int len, int cn)
|
||||
{
|
||||
ST result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
result += normL1<T, ST>(src, len*cn);
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
result += cv_abs(src[k]);
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename ST> int
|
||||
normL2_(const T* src, const uchar* mask, ST* _result, int len, int cn)
|
||||
{
|
||||
ST result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
result += normL2Sqr<T, ST>(src, len*cn);
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
{
|
||||
ST v = (ST)src[k];
|
||||
result += v*v;
|
||||
}
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
normInf_Bool(const uchar* src, const uchar* mask, int* _result, int len, int cn)
|
||||
{
|
||||
int result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
for ( int i = 0; i < len*cn; i++ ) {
|
||||
result = std::max(result, (int)(src[i] != 0));
|
||||
if (result != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
result = std::max(result, (int)(src[k] != 0));
|
||||
if (result != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
normL1_Bool(const uchar* src, const uchar* mask, int* _result, int len, int cn)
|
||||
{
|
||||
int result = *_result;
|
||||
if( !mask )
|
||||
{
|
||||
for ( int i = 0; i < len*cn; i++ )
|
||||
result += (int)(src[i] != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < len; i++, src += cn )
|
||||
if( mask[i] )
|
||||
{
|
||||
for( int k = 0; k < cn; k++ )
|
||||
result += (int)(src[k] != 0);
|
||||
}
|
||||
}
|
||||
*_result = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
normL2_Bool(const uchar* src, const uchar* mask, int* _result, int len, int cn)
|
||||
{
|
||||
return normL1_Bool(src, mask, _result, len, cn);
|
||||
}
|
||||
|
||||
#define CV_DEF_NORM_FUNC(L, suffix, type, ntype) \
|
||||
static int norm##L##_##suffix(const type* src, const uchar* mask, ntype* r, int len, int cn) \
|
||||
{ CV_INSTRUMENT_REGION(); return norm##L##_(src, mask, r, len, cn); } \
|
||||
|
||||
#define CV_DEF_NORM_ALL(suffix, type, inftype, l1type, l2type) \
|
||||
CV_DEF_NORM_FUNC(Inf, suffix, type, inftype) \
|
||||
CV_DEF_NORM_FUNC(L1, suffix, type, l1type) \
|
||||
CV_DEF_NORM_FUNC(L2, suffix, type, l2type)
|
||||
|
||||
CV_DEF_NORM_ALL(8u, uchar, int, int, int)
|
||||
CV_DEF_NORM_ALL(8s, schar, int, int, int)
|
||||
CV_DEF_NORM_ALL(16u, ushort, int, int, double)
|
||||
CV_DEF_NORM_ALL(16s, short, int, int, double)
|
||||
CV_DEF_NORM_ALL(32u, unsigned, unsigned, double, double)
|
||||
CV_DEF_NORM_ALL(32s, int, unsigned, double, double)
|
||||
CV_DEF_NORM_ALL(32f, float, float, double, double)
|
||||
CV_DEF_NORM_ALL(64f, double, double, double, double)
|
||||
CV_DEF_NORM_ALL(64u, uint64, uint64, double, double)
|
||||
CV_DEF_NORM_ALL(64s, int64, uint64, double, double)
|
||||
CV_DEF_NORM_ALL(16f, hfloat, float, float, float)
|
||||
CV_DEF_NORM_ALL(16bf, bfloat, float, float, float)
|
||||
|
||||
NormFunc getNormFunc(int normType, int depth)
|
||||
{
|
||||
static NormFunc normTab[3][CV_DEPTH_MAX] =
|
||||
{
|
||||
{
|
||||
(NormFunc)GET_OPTIMIZED(normInf_8u),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_8s),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_16u),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_16s),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_32s),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_32f),
|
||||
(NormFunc)normInf_64f,
|
||||
(NormFunc)GET_OPTIMIZED(normInf_16f),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_16bf),
|
||||
(NormFunc)normInf_Bool,
|
||||
(NormFunc)GET_OPTIMIZED(normInf_64u),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_64s),
|
||||
(NormFunc)GET_OPTIMIZED(normInf_32u),
|
||||
0
|
||||
},
|
||||
{
|
||||
(NormFunc)GET_OPTIMIZED(normL1_8u),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_8s),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_16u),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_16s),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_32s),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_32f),
|
||||
(NormFunc)normL1_64f,
|
||||
(NormFunc)GET_OPTIMIZED(normL1_16f),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_16bf),
|
||||
(NormFunc)normL1_Bool,
|
||||
(NormFunc)GET_OPTIMIZED(normL1_64u),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_64s),
|
||||
(NormFunc)GET_OPTIMIZED(normL1_32u),
|
||||
0
|
||||
},
|
||||
{
|
||||
(NormFunc)GET_OPTIMIZED(normL2_8u),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_8s),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_16u),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_16s),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_32s),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_32f),
|
||||
(NormFunc)normL2_64f,
|
||||
(NormFunc)GET_OPTIMIZED(normL2_16f),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_16bf),
|
||||
(NormFunc)normL2_Bool,
|
||||
(NormFunc)GET_OPTIMIZED(normL2_64u),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_64s),
|
||||
(NormFunc)GET_OPTIMIZED(normL2_32u),
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
return normTab[normType][depth];
|
||||
}
|
||||
|
||||
#endif // CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
|
||||
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_END
|
||||
|
||||
} // cv::
|
||||
+142
-147
@@ -42,168 +42,163 @@
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
enum
|
||||
enum HALFunc
|
||||
{
|
||||
HAL_EXP = 0,
|
||||
HAL_LOG = 1,
|
||||
HAL_SQRT = 2
|
||||
HAL_SQRT = 2,
|
||||
HAL_INV_SQRT = 3,
|
||||
HAL_LU = 4,
|
||||
HAL_CHOL = 5,
|
||||
};
|
||||
|
||||
TEST(Core_HAL, mathfuncs)
|
||||
void PrintTo(const HALFunc& v, std::ostream* os)
|
||||
{
|
||||
for( int hcase = 0; hcase < 6; hcase++ )
|
||||
{
|
||||
int depth = hcase % 2 == 0 ? CV_32F : CV_64F;
|
||||
double eps = depth == CV_32F ? 1e-5 : 1e-10;
|
||||
int nfunc = hcase / 2;
|
||||
int n = 100;
|
||||
|
||||
Mat src(1, n, depth), dst(1, n, depth), dst0(1, n, depth);
|
||||
randu(src, 1, 10);
|
||||
|
||||
double min_hal_t = DBL_MAX, min_ocv_t = DBL_MAX;
|
||||
|
||||
for( int iter = 0; iter < 10; iter++ )
|
||||
{
|
||||
double t = (double)getTickCount();
|
||||
switch (nfunc)
|
||||
{
|
||||
case HAL_EXP:
|
||||
if( depth == CV_32F )
|
||||
hal::exp32f(src.ptr<float>(), dst.ptr<float>(), n);
|
||||
else
|
||||
hal::exp64f(src.ptr<double>(), dst.ptr<double>(), n);
|
||||
break;
|
||||
case HAL_LOG:
|
||||
if( depth == CV_32F )
|
||||
hal::log32f(src.ptr<float>(), dst.ptr<float>(), n);
|
||||
else
|
||||
hal::log64f(src.ptr<double>(), dst.ptr<double>(), n);
|
||||
break;
|
||||
case HAL_SQRT:
|
||||
if( depth == CV_32F )
|
||||
hal::sqrt32f(src.ptr<float>(), dst.ptr<float>(), n);
|
||||
else
|
||||
hal::sqrt64f(src.ptr<double>(), dst.ptr<double>(), n);
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "unknown function");
|
||||
}
|
||||
t = (double)getTickCount() - t;
|
||||
min_hal_t = std::min(min_hal_t, t);
|
||||
|
||||
t = (double)getTickCount();
|
||||
switch (nfunc)
|
||||
{
|
||||
case HAL_EXP:
|
||||
exp(src, dst0);
|
||||
break;
|
||||
case HAL_LOG:
|
||||
log(src, dst0);
|
||||
break;
|
||||
case HAL_SQRT:
|
||||
pow(src, 0.5, dst0);
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "unknown function");
|
||||
}
|
||||
t = (double)getTickCount() - t;
|
||||
min_ocv_t = std::min(min_ocv_t, t);
|
||||
}
|
||||
EXPECT_LE(cvtest::norm(dst, dst0, NORM_INF | NORM_RELATIVE), eps);
|
||||
|
||||
double freq = getTickFrequency();
|
||||
printf("%s (N=%d, %s): hal time=%.2fusec, ocv time=%.2fusec\n",
|
||||
(nfunc == HAL_EXP ? "exp" : nfunc == HAL_LOG ? "log" : nfunc == HAL_SQRT ? "sqrt" : "???"),
|
||||
n, (depth == CV_32F ? "f32" : "f64"), min_hal_t*1e6/freq, min_ocv_t*1e6/freq);
|
||||
}
|
||||
switch (v) {
|
||||
case HAL_EXP: *os << "HAL_EXP"; return;
|
||||
case HAL_LOG: *os << "HAL_LOG"; return;
|
||||
case HAL_SQRT: *os << "HAL_SQRT"; return;
|
||||
case HAL_INV_SQRT: *os << "HAL_INV_SQRT"; return;
|
||||
case HAL_LU: *os << "LU"; return;
|
||||
case HAL_CHOL: *os << "Cholesky"; return;
|
||||
} // don't use "default:" to emit compiler warnings
|
||||
}
|
||||
|
||||
enum
|
||||
typedef testing::TestWithParam<std::tuple<int, HALFunc> > mathfuncs;
|
||||
TEST_P(mathfuncs, accuracy)
|
||||
{
|
||||
HAL_LU = 0,
|
||||
HAL_CHOL = 1
|
||||
};
|
||||
const int depth = std::get<0>(GetParam());
|
||||
const int nfunc = std::get<1>(GetParam());
|
||||
|
||||
typedef testing::TestWithParam<int> HAL;
|
||||
double eps = depth == CV_32F ? 1e-5 : 1e-10;
|
||||
int n = 100;
|
||||
|
||||
TEST_P(HAL, mat_decomp)
|
||||
{
|
||||
int hcase = GetParam();
|
||||
SCOPED_TRACE(cv::format("hcase=%d", hcase));
|
||||
Mat src(1, n, depth), dst(1, n, depth), dst0(1, n, depth);
|
||||
randu(src, 1, 10);
|
||||
|
||||
switch (nfunc)
|
||||
{
|
||||
int depth = hcase % 2 == 0 ? CV_32F : CV_64F;
|
||||
int size = (hcase / 2) % 4;
|
||||
size = size == 0 ? 3 : size == 1 ? 4 : size == 2 ? 6 : 15;
|
||||
int nfunc = (hcase / 8);
|
||||
#if CV_LASX
|
||||
double eps = depth == CV_32F ? 1e-5 : 2e-10;
|
||||
#else
|
||||
double eps = depth == CV_32F ? 1e-5 : 1e-10;
|
||||
#endif
|
||||
case HAL_EXP:
|
||||
if( depth == CV_32F )
|
||||
hal::exp32f(src.ptr<float>(), dst.ptr<float>(), n);
|
||||
else
|
||||
hal::exp64f(src.ptr<double>(), dst.ptr<double>(), n);
|
||||
break;
|
||||
case HAL_LOG:
|
||||
if( depth == CV_32F )
|
||||
hal::log32f(src.ptr<float>(), dst.ptr<float>(), n);
|
||||
else
|
||||
hal::log64f(src.ptr<double>(), dst.ptr<double>(), n);
|
||||
break;
|
||||
case HAL_SQRT:
|
||||
if( depth == CV_32F )
|
||||
hal::sqrt32f(src.ptr<float>(), dst.ptr<float>(), n);
|
||||
else
|
||||
hal::sqrt64f(src.ptr<double>(), dst.ptr<double>(), n);
|
||||
break;
|
||||
case HAL_INV_SQRT:
|
||||
if( depth == CV_32F )
|
||||
hal::invSqrt32f(src.ptr<float>(), dst.ptr<float>(), n);
|
||||
else
|
||||
hal::invSqrt64f(src.ptr<double>(), dst.ptr<double>(), n);
|
||||
break;
|
||||
|
||||
if( size == 3 )
|
||||
return; // TODO ???
|
||||
|
||||
Mat a0(size, size, depth), a(size, size, depth), b(size, 1, depth), x(size, 1, depth), x0(size, 1, depth);
|
||||
randu(a0, -1, 1);
|
||||
a0 = a0*a0.t();
|
||||
randu(b, -1, 1);
|
||||
|
||||
double min_hal_t = DBL_MAX, min_ocv_t = DBL_MAX;
|
||||
size_t asize = size*size*a.elemSize();
|
||||
size_t bsize = size*b.elemSize();
|
||||
|
||||
for( int iter = 0; iter < 10; iter++ )
|
||||
{
|
||||
memcpy(x.ptr(), b.ptr(), bsize);
|
||||
memcpy(a.ptr(), a0.ptr(), asize);
|
||||
|
||||
double t = (double)getTickCount();
|
||||
switch (nfunc)
|
||||
{
|
||||
case HAL_LU:
|
||||
if( depth == CV_32F )
|
||||
hal::LU32f(a.ptr<float>(), a.step, size, x.ptr<float>(), x.step, 1);
|
||||
else
|
||||
hal::LU64f(a.ptr<double>(), a.step, size, x.ptr<double>(), x.step, 1);
|
||||
break;
|
||||
case HAL_CHOL:
|
||||
if( depth == CV_32F )
|
||||
hal::Cholesky32f(a.ptr<float>(), a.step, size, x.ptr<float>(), x.step, 1);
|
||||
else
|
||||
hal::Cholesky64f(a.ptr<double>(), a.step, size, x.ptr<double>(), x.step, 1);
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "unknown function");
|
||||
}
|
||||
t = (double)getTickCount() - t;
|
||||
min_hal_t = std::min(min_hal_t, t);
|
||||
|
||||
t = (double)getTickCount();
|
||||
bool solveStatus = solve(a0, b, x0, (nfunc == HAL_LU ? DECOMP_LU : DECOMP_CHOLESKY));
|
||||
t = (double)getTickCount() - t;
|
||||
EXPECT_TRUE(solveStatus);
|
||||
min_ocv_t = std::min(min_ocv_t, t);
|
||||
}
|
||||
//std::cout << "x: " << Mat(x.t()) << std::endl;
|
||||
//std::cout << "x0: " << Mat(x0.t()) << std::endl;
|
||||
|
||||
EXPECT_LE(cvtest::norm(x, x0, NORM_INF | NORM_RELATIVE), eps)
|
||||
<< "x: " << Mat(x.t())
|
||||
<< "\nx0: " << Mat(x0.t())
|
||||
<< "\na0: " << a0
|
||||
<< "\nb: " << b;
|
||||
|
||||
double freq = getTickFrequency();
|
||||
printf("%s (%d x %d, %s): hal time=%.2fusec, ocv time=%.2fusec\n",
|
||||
(nfunc == HAL_LU ? "LU" : nfunc == HAL_CHOL ? "Cholesky" : "???"),
|
||||
size, size,
|
||||
(depth == CV_32F ? "f32" : "f64"),
|
||||
min_hal_t*1e6/freq, min_ocv_t*1e6/freq);
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "unknown function");
|
||||
}
|
||||
|
||||
src.copyTo(dst0);
|
||||
switch (nfunc)
|
||||
{
|
||||
case HAL_EXP:
|
||||
if( depth == CV_32F )
|
||||
dst0.forEach<float>([](float& v, const int*) -> void { v = std::exp(v); });
|
||||
else
|
||||
dst0.forEach<double>([](double& v, const int*) -> void { v = std::exp(v); });
|
||||
break;
|
||||
case HAL_LOG:
|
||||
if( depth == CV_32F )
|
||||
dst0.forEach<float>([](float& v, const int*) -> void { v = std::log(v); });
|
||||
else
|
||||
dst0.forEach<double>([](double& v, const int*) -> void { v = std::log(v); });
|
||||
break;
|
||||
case HAL_SQRT:
|
||||
if( depth == CV_32F )
|
||||
dst0.forEach<float>([](float& v, const int*) -> void { v = std::sqrt(v); });
|
||||
else
|
||||
dst0.forEach<double>([](double& v, const int*) -> void { v = std::sqrt(v); });
|
||||
break;
|
||||
case HAL_INV_SQRT:
|
||||
if( depth == CV_32F )
|
||||
dst0.forEach<float>([](float& v, const int*) -> void { v = std::pow(v, -0.5f); });
|
||||
else
|
||||
dst0.forEach<double>([](double& v, const int*) -> void { v = std::pow(v, -0.5); });
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "unknown function");
|
||||
}
|
||||
EXPECT_LE(cvtest::norm(dst, dst0, NORM_INF | NORM_RELATIVE), eps);
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(Core_HAL, mathfuncs,
|
||||
testing::Combine(
|
||||
testing::Values(CV_32F, CV_64F),
|
||||
testing::Values(HAL_EXP, HAL_LOG, HAL_SQRT, HAL_INV_SQRT)
|
||||
)
|
||||
);
|
||||
|
||||
typedef testing::TestWithParam<std::tuple<int, HALFunc, int> > mat_decomp;
|
||||
TEST_P(mat_decomp, accuracy)
|
||||
{
|
||||
const int depth = std::get<0>(GetParam());
|
||||
const int nfunc = std::get<1>(GetParam());
|
||||
const int size = std::get<2>(GetParam());
|
||||
|
||||
#if CV_LASX
|
||||
double eps = depth == CV_32F ? 1e-5 : 2e-10;
|
||||
#else
|
||||
double eps = depth == CV_32F ? 1e-5 : 1e-10;
|
||||
#endif
|
||||
|
||||
Mat a0(size, size, depth), x0(size, 1, depth);
|
||||
randu(a0, -1, 1);
|
||||
a0 = a0*a0.t();
|
||||
randu(x0, -1, 1);
|
||||
Mat b = a0 * x0;
|
||||
Mat x = b.clone();
|
||||
Mat a = a0.clone();
|
||||
|
||||
int solveStatus;
|
||||
switch (nfunc)
|
||||
{
|
||||
case HAL_LU:
|
||||
if( depth == CV_32F )
|
||||
solveStatus = hal::LU32f(a.ptr<float>(), a.step, size, x.ptr<float>(), x.step, 1);
|
||||
else
|
||||
solveStatus = hal::LU64f(a.ptr<double>(), a.step, size, x.ptr<double>(), x.step, 1);
|
||||
break;
|
||||
case HAL_CHOL:
|
||||
if( depth == CV_32F )
|
||||
solveStatus = hal::Cholesky32f(a.ptr<float>(), a.step, size, x.ptr<float>(), x.step, 1);
|
||||
else
|
||||
solveStatus = hal::Cholesky64f(a.ptr<double>(), a.step, size, x.ptr<double>(), x.step, 1);
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "unknown function");
|
||||
}
|
||||
EXPECT_NE(0, solveStatus);
|
||||
EXPECT_LE(cvtest::norm(a0 * x, b, NORM_INF | NORM_RELATIVE), eps)
|
||||
<< "x: " << Mat(x.t())
|
||||
<< "\nx0: " << Mat(x0.t())
|
||||
<< "\na0: " << a0
|
||||
<< "\nb: " << b;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Core, HAL, testing::Range(0, 16));
|
||||
INSTANTIATE_TEST_CASE_P(Core_HAL, mat_decomp,
|
||||
testing::Combine(
|
||||
testing::Values(CV_32F, CV_64F),
|
||||
testing::Values(HAL_LU, HAL_CHOL),
|
||||
testing::Values(3, 4, 6, 15)
|
||||
)
|
||||
);
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -24,7 +24,6 @@ GifDecoder::GifDecoder() {
|
||||
hasRead = false;
|
||||
hasTransparentColor = false;
|
||||
transparentColor = 0;
|
||||
opMode = GRFMT_GIF_Nothing;
|
||||
top = 0, left = 0, width = 0, height = 0;
|
||||
depth = 8;
|
||||
idx = 0;
|
||||
@@ -66,6 +65,8 @@ bool GifDecoder::readHeader() {
|
||||
for (int i = 0; i < 3 * globalColorTableSize; i++) {
|
||||
globalColorTable[i] = (uchar)m_strm.getByte();
|
||||
}
|
||||
CV_CheckGE(bgColor, 0, "bgColor should be >= 0");
|
||||
CV_CheckLT(bgColor, globalColorTableSize, "bgColor should be < globalColorTableSize");
|
||||
}
|
||||
|
||||
// get the frame count
|
||||
@@ -81,7 +82,8 @@ bool GifDecoder::readData(Mat &img) {
|
||||
return true;
|
||||
}
|
||||
|
||||
readExtensions();
|
||||
const GifDisposeMethod disposalMethod = readExtensions();
|
||||
|
||||
// Image separator
|
||||
CV_Assert(!(m_strm.getByte()^0x2C));
|
||||
left = m_strm.getWord();
|
||||
@@ -93,38 +95,50 @@ bool GifDecoder::readData(Mat &img) {
|
||||
imgCodeStream.resize(width * height);
|
||||
Mat img_;
|
||||
|
||||
switch (opMode) {
|
||||
case GifOpMode::GRFMT_GIF_PreviousImage:
|
||||
if (lastImage.empty()){
|
||||
img_ = Mat::zeros(m_height, m_width, CV_8UC4);
|
||||
} else {
|
||||
img_ = lastImage;
|
||||
if (lastImage.empty())
|
||||
{
|
||||
Scalar background(0.0, 0.0, 0.0, 0.0);
|
||||
if (bgColor < globalColorTableSize)
|
||||
{
|
||||
background = Scalar( globalColorTable[bgColor * 3 + 2], // B
|
||||
globalColorTable[bgColor * 3 + 1], // G
|
||||
globalColorTable[bgColor * 3 + 0], // R
|
||||
0); // A
|
||||
}
|
||||
img_ = Mat(m_height, m_width, CV_8UC4, background);
|
||||
} else {
|
||||
img_ = lastImage;
|
||||
}
|
||||
lastImage.release();
|
||||
|
||||
Mat restore;
|
||||
switch(disposalMethod)
|
||||
{
|
||||
case GIF_DISPOSE_NA:
|
||||
case GIF_DISPOSE_NONE:
|
||||
// Do nothing
|
||||
break;
|
||||
case GIF_DISPOSE_RESTORE_BACKGROUND:
|
||||
if (bgColor < globalColorTableSize)
|
||||
{
|
||||
const Scalar background = Scalar( globalColorTable[bgColor * 3 + 2], // B
|
||||
globalColorTable[bgColor * 3 + 1], // G
|
||||
globalColorTable[bgColor * 3 + 0], // R
|
||||
0); // A
|
||||
restore = Mat(width, height, CV_8UC4, background);
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_LOG_WARNING(NULL, cv::format("bgColor(%d) is out of globalColorTableSize(%d)", bgColor, globalColorTableSize));
|
||||
}
|
||||
break;
|
||||
case GifOpMode::GRFMT_GIF_Background:
|
||||
// background color is valid iff global color table exists
|
||||
CV_Assert(globalColorTableSize > 0);
|
||||
if (hasTransparentColor && transparentColor == bgColor) {
|
||||
img_ = Mat(m_height, m_width, CV_8UC4,
|
||||
Scalar(globalColorTable[bgColor * 3 + 2],
|
||||
globalColorTable[bgColor * 3 + 1],
|
||||
globalColorTable[bgColor * 3], 0));
|
||||
} else {
|
||||
img_ = Mat(m_height, m_width, CV_8UC4,
|
||||
Scalar(globalColorTable[bgColor * 3 + 2],
|
||||
globalColorTable[bgColor * 3 + 1],
|
||||
globalColorTable[bgColor * 3], 255));
|
||||
}
|
||||
break;
|
||||
case GifOpMode::GRFMT_GIF_Nothing:
|
||||
case GifOpMode::GRFMT_GIF_Cover:
|
||||
// default value
|
||||
img_ = Mat::zeros(m_height, m_width, CV_8UC4);
|
||||
case GIF_DISPOSE_RESTORE_PREVIOUS:
|
||||
restore = Mat(img_, cv::Rect(left,top,width,height)).clone();
|
||||
break;
|
||||
default:
|
||||
CV_Assert(false);
|
||||
break;
|
||||
}
|
||||
lastImage.release();
|
||||
|
||||
auto flags = (uchar)m_strm.getByte();
|
||||
if (flags & 0x80) {
|
||||
@@ -189,6 +203,13 @@ bool GifDecoder::readData(Mat &img) {
|
||||
// release the memory
|
||||
img_.release();
|
||||
|
||||
// update lastImage to dispose current frame.
|
||||
if(!restore.empty())
|
||||
{
|
||||
Mat roi = Mat(lastImage, cv::Rect(left,top,width,height));
|
||||
restore.copyTo(roi);
|
||||
}
|
||||
|
||||
return hasRead;
|
||||
}
|
||||
|
||||
@@ -212,8 +233,9 @@ bool GifDecoder::nextPage() {
|
||||
}
|
||||
}
|
||||
|
||||
void GifDecoder::readExtensions() {
|
||||
GifDisposeMethod GifDecoder::readExtensions() {
|
||||
uchar len;
|
||||
GifDisposeMethod disposalMethod = GifDisposeMethod::GIF_DISPOSE_NA;
|
||||
while (!(m_strm.getByte() ^ 0x21)) {
|
||||
auto extensionType = (uchar)m_strm.getByte();
|
||||
|
||||
@@ -221,13 +243,19 @@ void GifDecoder::readExtensions() {
|
||||
// the scope of this extension is the next image or plain text extension
|
||||
if (!(extensionType ^ 0xF9)) {
|
||||
hasTransparentColor = false;
|
||||
opMode = GifOpMode::GRFMT_GIF_Nothing;// default value
|
||||
len = (uchar)m_strm.getByte();
|
||||
CV_Assert(len == 4);
|
||||
auto flags = (uchar)m_strm.getByte();
|
||||
const uint8_t packedFields = (uchar)m_strm.getByte();
|
||||
|
||||
const uint8_t dm = (packedFields >> GIF_DISPOSE_METHOD_SHIFT) & GIF_DISPOSE_METHOD_MASK;
|
||||
CV_CheckLE(dm, GIF_DISPOSE_MAX, "Unsupported Dispose Method");
|
||||
disposalMethod = static_cast<GifDisposeMethod>(dm);
|
||||
|
||||
const uint8_t transColorFlag = packedFields & GIF_TRANS_COLOR_FLAG_MASK;
|
||||
CV_CheckLE(transColorFlag, GIF_TRANSPARENT_INDEX_MAX, "Unsupported Transparent Color Flag");
|
||||
hasTransparentColor = (transColorFlag == GIF_TRANSPARENT_INDEX_GIVEN);
|
||||
|
||||
m_animation.durations.push_back(m_strm.getWord() * 10); // delay time
|
||||
opMode = (GifOpMode)((flags & 0x1C) >> 2);
|
||||
hasTransparentColor = flags & 0x01;
|
||||
transparentColor = (uchar)m_strm.getByte();
|
||||
}
|
||||
|
||||
@@ -240,6 +268,8 @@ void GifDecoder::readExtensions() {
|
||||
}
|
||||
// roll back to the block identifier
|
||||
m_strm.setPos(m_strm.getPos() - 1);
|
||||
|
||||
return disposalMethod;
|
||||
}
|
||||
|
||||
void GifDecoder::code2pixel(Mat& img, int start, int k){
|
||||
@@ -247,23 +277,6 @@ void GifDecoder::code2pixel(Mat& img, int start, int k){
|
||||
for (int j = 0; j < width; j++) {
|
||||
uchar colorIdx = imgCodeStream[idx++];
|
||||
if (hasTransparentColor && colorIdx == transparentColor) {
|
||||
if (opMode != GifOpMode::GRFMT_GIF_PreviousImage) {
|
||||
if (colorIdx < localColorTableSize) {
|
||||
img.at<Vec4b>(top + i, left + j) =
|
||||
Vec4b(localColorTable[colorIdx * 3 + 2], // B
|
||||
localColorTable[colorIdx * 3 + 1], // G
|
||||
localColorTable[colorIdx * 3], // R
|
||||
0); // A
|
||||
} else if (colorIdx < globalColorTableSize) {
|
||||
img.at<Vec4b>(top + i, left + j) =
|
||||
Vec4b(globalColorTable[colorIdx * 3 + 2], // B
|
||||
globalColorTable[colorIdx * 3 + 1], // G
|
||||
globalColorTable[colorIdx * 3], // R
|
||||
0); // A
|
||||
} else {
|
||||
img.at<Vec4b>(top + i, left + j) = Vec4b(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (colorIdx < localColorTableSize) {
|
||||
@@ -437,14 +450,10 @@ bool GifDecoder::getFrameCount_() {
|
||||
int len = m_strm.getByte();
|
||||
while (len) {
|
||||
if (len == 4) {
|
||||
int packedFields = m_strm.getByte();
|
||||
// 3 bit : Reserved
|
||||
// 3 bit : Disposal Method
|
||||
// 1 bit : User Input Flag
|
||||
// 1 bit : Transparent Color Flag
|
||||
if ( (packedFields & 0x01)== 0x01) {
|
||||
m_type = CV_8UC4; // Transparent Index is given.
|
||||
}
|
||||
const uint8_t packedFields = static_cast<uint8_t>(m_strm.getByte()); // Packed Fields
|
||||
const uint8_t transColorFlag = packedFields & GIF_TRANS_COLOR_FLAG_MASK;
|
||||
CV_CheckLE(transColorFlag, GIF_TRANSPARENT_INDEX_MAX, "Unsupported Transparent Color Flag");
|
||||
m_type = (transColorFlag == GIF_TRANSPARENT_INDEX_GIVEN) ? CV_8UC4 : CV_8UC3;
|
||||
m_strm.skip(2); // Delay Time
|
||||
m_strm.skip(1); // Transparent Color Index
|
||||
} else {
|
||||
@@ -518,7 +527,6 @@ GifEncoder::GifEncoder() {
|
||||
m_height = 0, m_width = 0;
|
||||
width = 0, height = 0, top = 0, left = 0;
|
||||
m_buf_supported = true;
|
||||
opMode = GRFMT_GIF_Cover;
|
||||
transparentColor = 0; // index of the transparent color, default 0. currently it is a constant number
|
||||
transparentRGB = Vec3b(0, 0, 0); // the transparent color, default black
|
||||
lzwMaxCodeSize = 12; // the maximum code size, default 12. currently it is a constant number
|
||||
@@ -665,11 +673,9 @@ bool GifEncoder::writeFrame(const Mat &img) {
|
||||
strm.putByte(0x21); // extension introducer
|
||||
strm.putByte(0xF9); // graphic control label
|
||||
strm.putByte(0x04); // block size, fixed number
|
||||
// flag is a packed field, and the first 3 bits are reserved
|
||||
uchar flag = opMode << 2;
|
||||
if (criticalTransparency)
|
||||
flag |= 1;
|
||||
strm.putByte(flag);
|
||||
const int gcePackedFields = static_cast<int>(GIF_DISPOSE_RESTORE_PREVIOUS << GIF_DISPOSE_METHOD_SHIFT) |
|
||||
static_cast<int>(criticalTransparency ? GIF_TRANSPARENT_INDEX_GIVEN : GIF_TRANSPARENT_INDEX_NOT_GIVEN);
|
||||
strm.putByte(gcePackedFields);
|
||||
strm.putWord(frameDelay);
|
||||
strm.putByte(transparentColor);
|
||||
strm.putByte(0x00); // end of the extension
|
||||
@@ -680,7 +686,7 @@ bool GifEncoder::writeFrame(const Mat &img) {
|
||||
strm.putWord(top);
|
||||
strm.putWord(width);
|
||||
strm.putWord(height);
|
||||
flag = localColorTableSize > 0 ? 0x80 : 0x00;
|
||||
uint8_t flag = localColorTableSize > 0 ? 0x80 : 0x00;
|
||||
if (localColorTableSize > 0) {
|
||||
std::vector<Mat> img_vec(1, img);
|
||||
getColorTable(img_vec, false);
|
||||
|
||||
@@ -11,14 +11,35 @@
|
||||
namespace cv
|
||||
{
|
||||
|
||||
enum GifOpMode
|
||||
{
|
||||
GRFMT_GIF_Nothing = 0,
|
||||
GRFMT_GIF_PreviousImage = 1,
|
||||
GRFMT_GIF_Background = 2,
|
||||
GRFMT_GIF_Cover = 3
|
||||
// See https://www.w3.org/Graphics/GIF/spec-gif89a.txt
|
||||
// 23. Graphic Control Extension.
|
||||
// <Packed Fields>
|
||||
// Reserved : 3 bits
|
||||
// Disposal Method : 3 bits
|
||||
// User Input Flag : 1 bit
|
||||
// Transparent Color Flag : 1 bit
|
||||
constexpr int GIF_DISPOSE_METHOD_SHIFT = 2;
|
||||
constexpr int GIF_DISPOSE_METHOD_MASK = 7; // 0b111
|
||||
constexpr int GIF_TRANS_COLOR_FLAG_MASK = 1; // 0b1
|
||||
|
||||
enum GifDisposeMethod {
|
||||
GIF_DISPOSE_NA = 0,
|
||||
GIF_DISPOSE_NONE = 1,
|
||||
GIF_DISPOSE_RESTORE_BACKGROUND = 2,
|
||||
GIF_DISPOSE_RESTORE_PREVIOUS = 3,
|
||||
// 4-7 are reserved/undefined.
|
||||
|
||||
GIF_DISPOSE_MAX = GIF_DISPOSE_RESTORE_PREVIOUS,
|
||||
};
|
||||
|
||||
enum GifTransparentColorFlag {
|
||||
GIF_TRANSPARENT_INDEX_NOT_GIVEN = 0,
|
||||
GIF_TRANSPARENT_INDEX_GIVEN = 1,
|
||||
|
||||
GIF_TRANSPARENT_INDEX_MAX = GIF_TRANSPARENT_INDEX_GIVEN,
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//// GIF Decoder ////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@@ -43,7 +64,6 @@ protected:
|
||||
int depth;
|
||||
int idx;
|
||||
|
||||
GifOpMode opMode;
|
||||
bool hasTransparentColor;
|
||||
uchar transparentColor;
|
||||
int top, left, width, height;
|
||||
@@ -66,7 +86,7 @@ protected:
|
||||
std::vector<uchar> prefix;
|
||||
};
|
||||
|
||||
void readExtensions();
|
||||
GifDisposeMethod readExtensions();
|
||||
void code2pixel(Mat& img, int start, int k);
|
||||
bool lzwDecode();
|
||||
bool getFrameCount_();
|
||||
|
||||
@@ -366,6 +366,54 @@ TEST(Imgcodecs_Gif, encode_IMREAD_GRAYSCALE) {
|
||||
EXPECT_EQ(decoded.channels(), 1);
|
||||
}
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/26924
|
||||
TEST(Imgcodecs_Gif, decode_disposal_method)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "gifsuite/disposalMethod.gif";
|
||||
cv::Animation anim;
|
||||
bool ret = false;
|
||||
EXPECT_NO_THROW(ret = imreadanimation(filename, anim, cv::IMREAD_UNCHANGED));
|
||||
EXPECT_TRUE(ret);
|
||||
|
||||
/* [Detail of this test]
|
||||
* disposalMethod.gif has 5 frames to draw 8x8 rectangles with each color index, offsets and disposal method.
|
||||
* frame 1 draws {1, ... ,1} rectangle at (1,1) with DisposalMethod = 0.
|
||||
* frame 2 draws {2, ... ,2} rectangle at (2,2) with DisposalMethod = 3.
|
||||
* frame 3 draws {3, ... ,3} rectangle at (3,3) with DisposalMethod = 1.
|
||||
* frame 4 draws {4, ... ,4} rectangle at (4,4) with DisposalMethod = 2.
|
||||
* frame 5 draws {5, ... ,5} rectangle at (5,5) with DisposalMethod = 1.
|
||||
*
|
||||
* To convenience to test, color[N] in the color table has RGB(32*N, some, some).
|
||||
* color[0] = RGB(0,0,0) (background color).
|
||||
* color[1] = RGB(32,0,0)
|
||||
* color[2] = RGB(64,0,255)
|
||||
* color[3] = RGB(96,255,0)
|
||||
* color[4] = RGB(128,128,128)
|
||||
* color[5] = RGB(160,255,255)
|
||||
*/
|
||||
const int refIds[5][6] =
|
||||
{// { 0, 0, 0, 0, 0, 0} 0 is background color.
|
||||
{ 0, 1, 1, 1, 1, 1}, // 1 is to be not disposed.
|
||||
{ 0, 1, 2, 2, 2, 2}, // 2 is to be restored to previous.
|
||||
{ 0, 1, 1, 3, 3, 3}, // 3 is to be left in place.
|
||||
{ 0, 1, 1, 3, 4, 4}, // 4 is to be restored to the background color.
|
||||
{ 0, 1, 1, 3, 0, 5}, // 5 is to be left in place.
|
||||
};
|
||||
|
||||
for(int i = 0 ; i < 5; i++)
|
||||
{
|
||||
cv::Mat frame = anim.frames[i];
|
||||
EXPECT_FALSE(frame.empty());
|
||||
EXPECT_EQ(frame.type(), CV_8UC4);
|
||||
for(int j = 0; j < 6; j ++ )
|
||||
{
|
||||
const cv::Scalar p = frame.at<Vec4b>(j,j);
|
||||
EXPECT_EQ( p[2], refIds[i][j] * 32 ) << " i = " << i << " j = " << j << " pixels = " << p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}//opencv_test
|
||||
}//namespace
|
||||
|
||||
|
||||
@@ -327,6 +327,38 @@ const string pngsuite_files_corrupted[] = {
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_PngSuite_Corrupted,
|
||||
testing::ValuesIn(pngsuite_files_corrupted));
|
||||
|
||||
typedef testing::TestWithParam<testing::tuple<string, int, size_t>> Imgcodecs_Png_ImwriteFlags;
|
||||
|
||||
TEST_P(Imgcodecs_Png_ImwriteFlags, compression_level)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + get<0>(GetParam());
|
||||
|
||||
const int compression_level = get<1>(GetParam());
|
||||
const size_t compression_level_output_size = get<2>(GetParam());
|
||||
|
||||
Mat src = imread(filename, IMREAD_UNCHANGED);
|
||||
EXPECT_FALSE(src.empty()) << "Cannot read test image " << filename;
|
||||
|
||||
vector<uchar> buf;
|
||||
imencode(".png", src, buf, { IMWRITE_PNG_COMPRESSION, compression_level });
|
||||
EXPECT_EQ(buf.size(), compression_level_output_size);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/,
|
||||
Imgcodecs_Png_ImwriteFlags,
|
||||
testing::Values(
|
||||
make_tuple("../perf/512x512.png", 0, 788279),
|
||||
make_tuple("../perf/512x512.png", 1, 179503),
|
||||
make_tuple("../perf/512x512.png", 2, 176007),
|
||||
make_tuple("../perf/512x512.png", 3, 170497),
|
||||
make_tuple("../perf/512x512.png", 4, 163357),
|
||||
make_tuple("../perf/512x512.png", 5, 159190),
|
||||
make_tuple("../perf/512x512.png", 6, 156621),
|
||||
make_tuple("../perf/512x512.png", 7, 155696),
|
||||
make_tuple("../perf/512x512.png", 8, 153708),
|
||||
make_tuple("../perf/512x512.png", 9, 152181)));
|
||||
|
||||
#endif // HAVE_PNG
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -3572,7 +3572,7 @@ cv::Matx23d cv::getRotationMatrix2D_(Point2f center, double angle, double scale)
|
||||
* vi = ---------------------
|
||||
* c20*xi + c21*yi + c22
|
||||
*
|
||||
* Coefficients are calculated by solving linear system:
|
||||
* Coefficients are calculated by solving one of 2 linear systems:
|
||||
* / x0 y0 1 0 0 0 -x0*u0 -y0*u0 \ /c00\ /u0\
|
||||
* | x1 y1 1 0 0 0 -x1*u1 -y1*u1 | |c01| |u1|
|
||||
* | x2 y2 1 0 0 0 -x2*u2 -y2*u2 | |c02| |u2|
|
||||
@@ -3584,12 +3584,28 @@ cv::Matx23d cv::getRotationMatrix2D_(Point2f center, double angle, double scale)
|
||||
*
|
||||
* where:
|
||||
* cij - matrix coefficients, c22 = 1
|
||||
*
|
||||
* or
|
||||
*
|
||||
* / x0 y0 1 0 0 0 -x0*u0 -y0*u0 -u0 \ /c00\ /0\
|
||||
* | x1 y1 1 0 0 0 -x1*u1 -y1*u1 -u1 | |c01| |0|
|
||||
* | x2 y2 1 0 0 0 -x2*u2 -y2*u2 -u2 | |c02| |0|
|
||||
* | x3 y3 1 0 0 0 -x3*u3 -y3*u3 -u3 |.|c10|=|0|,
|
||||
* | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 -v0 | |c11| |0|
|
||||
* | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 -v1 | |c12| |0|
|
||||
* | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 -v2 | |c20| |0|
|
||||
* \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 -v3 / |c21| \0/
|
||||
* \c22/
|
||||
*
|
||||
* where:
|
||||
* cij - matrix coefficients, c00^2 + c01^2 + c02^2 + c10^2 + c11^2 + c12^2 + c20^2 + c21^2 + c22^2 = 1
|
||||
*/
|
||||
cv::Mat cv::getPerspectiveTransform(const Point2f src[], const Point2f dst[], int solveMethod)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat M(3, 3, CV_64F), X(8, 1, CV_64F, M.ptr());
|
||||
// try c22 = 1
|
||||
Mat M(3, 3, CV_64F), X8(8, 1, CV_64F, M.ptr());
|
||||
double a[8][8], b[8];
|
||||
Mat A(8, 8, CV_64F, a), B(8, 1, CV_64F, b);
|
||||
|
||||
@@ -3608,8 +3624,24 @@ cv::Mat cv::getPerspectiveTransform(const Point2f src[], const Point2f dst[], in
|
||||
b[i+4] = dst[i].y;
|
||||
}
|
||||
|
||||
solve(A, B, X, solveMethod);
|
||||
M.ptr<double>()[8] = 1.;
|
||||
if (solve(A, B, X8, solveMethod) && norm(A * X8, B) < 1e-8)
|
||||
{
|
||||
M.ptr<double>()[8] = 1.;
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
// c00^2 + c01^2 + c02^2 + c10^2 + c11^2 + c12^2 + c20^2 + c21^2 + c22^2 = 1
|
||||
hconcat(A, -B, A);
|
||||
|
||||
Mat AtA;
|
||||
mulTransposed(A, AtA, true);
|
||||
|
||||
Mat D, U;
|
||||
SVDecomp(AtA, D, U, noArray());
|
||||
|
||||
Mat X9(9, 1, CV_64F, M.ptr());
|
||||
U.col(8).copyTo(X9);
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
@@ -1131,5 +1131,40 @@ TEST(Imgproc_Resize, issue_26497)
|
||||
EXPECT_LE(maxv, 3.);
|
||||
}
|
||||
|
||||
TEST(Imgproc_getPerspectiveTransform, issue_26916)
|
||||
{
|
||||
double src_data[] = {320, 512, 960, 512, 0, 1024, 1280, 1024};
|
||||
const Mat src_points(4, 2, CV_64FC1, src_data);
|
||||
|
||||
double dst_data[] = {0, 0, 1280, 0, 0, 1024, 1280, 1024};
|
||||
const Mat dst_points(4, 2, CV_64FC1, dst_data);
|
||||
|
||||
Mat src_points_f;
|
||||
src_points.convertTo(src_points_f, CV_32FC1);
|
||||
|
||||
Mat dst_points_f;
|
||||
dst_points.convertTo(dst_points_f, CV_32FC1);
|
||||
|
||||
Mat perspective_transform = getPerspectiveTransform(src_points_f, dst_points_f);
|
||||
EXPECT_NEAR(perspective_transform.at<double>(2, 2), 0, 1e-16);
|
||||
EXPECT_NEAR(cv::norm(perspective_transform), 1, 1e-14);
|
||||
|
||||
const Mat ones = Mat::ones(4, 1, CV_64FC1);
|
||||
|
||||
Mat homogeneous_src_points;
|
||||
hconcat(src_points, ones, homogeneous_src_points);
|
||||
|
||||
Mat obtained_homogeneous_dst_points = (perspective_transform * homogeneous_src_points.t()).t();
|
||||
for (int row = 0; row < 4; ++row)
|
||||
{
|
||||
obtained_homogeneous_dst_points.row(row) /= obtained_homogeneous_dst_points.at<double>(row, 2);
|
||||
}
|
||||
|
||||
Mat expected_homogeneous_dst_points;
|
||||
hconcat(dst_points, ones, expected_homogeneous_dst_points);
|
||||
|
||||
EXPECT_MAT_NEAR(obtained_homogeneous_dst_points, expected_homogeneous_dst_points, 1e-10);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
/* End of file. */
|
||||
|
||||
@@ -49,7 +49,7 @@ class NewOpenCVTests(unittest.TestCase):
|
||||
filepath = self.find_file(filename)
|
||||
with open(filepath, 'rb') as f:
|
||||
filedata = f.read()
|
||||
self.image_cache[filename] = cv.imdecode(np.fromstring(filedata, dtype=np.uint8), iscolor)
|
||||
self.image_cache[filename] = cv.imdecode(np.frombuffer(filedata, dtype=np.uint8), iscolor)
|
||||
return self.image_cache[filename]
|
||||
|
||||
def setUp(self):
|
||||
|
||||
@@ -2344,21 +2344,33 @@ void filterSpecklesImpl(cv::Mat& img, int newVal, int maxSpeckleSize, int maxDif
|
||||
using namespace cv;
|
||||
|
||||
int width = img.cols, height = img.rows, npixels = width*height;
|
||||
size_t bufSize = npixels*(int)(sizeof(Point2s) + sizeof(int) + sizeof(uchar));
|
||||
// space allocation for:
|
||||
// labels : npixels * sizeof(int)
|
||||
// wbuf : npixels * sizeof(Point2s)
|
||||
// rtype : (npixels + 1) * sizeof(uchar)
|
||||
size_t bufSize = npixels * sizeof(int) // for labels
|
||||
+ npixels * sizeof(Point2s) // for wavefront buffer (wbuf)
|
||||
+ (npixels + 1) * sizeof(uchar); // for region type (rtype)
|
||||
if( !_buf.isContinuous() || _buf.empty() || _buf.cols*_buf.rows*_buf.elemSize() < bufSize )
|
||||
_buf.reserveBuffer(bufSize);
|
||||
|
||||
uchar* buf = _buf.ptr();
|
||||
int i, j, dstep = (int)(img.step/sizeof(T));
|
||||
|
||||
// store labels and their corresponding region types
|
||||
int* labels = (int*)buf;
|
||||
buf += npixels*sizeof(labels[0]);
|
||||
// store wavefront
|
||||
Point2s* wbuf = (Point2s*)buf;
|
||||
buf += npixels*sizeof(wbuf[0]);
|
||||
// store region type
|
||||
uchar* rtype = (uchar*)buf;
|
||||
buf += (npixels + 1) * sizeof(rtype[0]);
|
||||
int curlabel = 0;
|
||||
|
||||
// clear out label assignments
|
||||
// clear out label and rtype buffers
|
||||
memset(labels, 0, npixels*sizeof(labels[0]));
|
||||
memset(rtype, 0, (npixels + 1)*sizeof(rtype[0]));
|
||||
|
||||
for( i = 0; i < height; i++ )
|
||||
{
|
||||
|
||||
@@ -49,5 +49,9 @@ if(OPENCV_DISABLE_THREAD_SUPPORT)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
|
||||
ocv_target_link_libraries(${the_module} PUBLIC regex)
|
||||
endif()
|
||||
include(CheckLibraryExists)
|
||||
CHECK_LIBRARY_EXISTS(regex regexec "" HAVE_REGEX_LIBRARY)
|
||||
if(HAVE_REGEX_LIBRARY)
|
||||
ocv_target_link_libraries(${the_module} PUBLIC regex)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -10,7 +10,7 @@ Video I/O with OpenCV Overview {#videoio_overview}
|
||||
General Information
|
||||
-------------------
|
||||
|
||||
The OpenCV @ref videoio module is a set of classes and functions to read and write video or images sequence.
|
||||
The OpenCV @ref videoio module is a set of classes and functions to read and write video or images sequences.
|
||||
|
||||
Basically, the module provides the cv::VideoCapture and cv::VideoWriter classes as 2-layer interface to many video
|
||||
I/O APIs used as backend.
|
||||
@@ -20,7 +20,7 @@ I/O APIs used as backend.
|
||||
Some backends such as Direct Show (DSHOW), Microsoft Media Foundation (MSMF),
|
||||
Video 4 Linux (V4L), etc... are interfaces to the video I/O library provided by the operating system.
|
||||
|
||||
Some others backends like OpenNI2 for Kinect, Intel Perceptual Computing SDK, GStreamer,
|
||||
Some other backends like OpenNI2 for Kinect, Intel Perceptual Computing SDK, GStreamer,
|
||||
XIMEA Camera API, etc... are interfaces to proprietary drivers or to external library.
|
||||
|
||||
See the list of supported backends here: cv::VideoCaptureAPIs
|
||||
@@ -84,8 +84,7 @@ for the operating system. Thus you can't use VideoCapture or VideoWriter with t
|
||||
To get access to their devices, manufactures provide their own C++ API and library that you have to
|
||||
include and link with your OpenCV application.
|
||||
|
||||
It is a common case that these libraries read/write images from/to a memory buffer. If it so, it is
|
||||
possible to make a `Mat` header for memory buffer (user-allocated data) and process it
|
||||
It is a common case that these libraries read/write images from/to a memory buffer. If so, it is possible to make a `Mat` header for memory buffer (user-allocated data) and process it
|
||||
in-place using OpenCV functions. See cv::Mat::Mat() for more details.
|
||||
|
||||
|
||||
@@ -93,7 +92,7 @@ The FFmpeg library
|
||||
------------------
|
||||
|
||||
OpenCV can use the FFmpeg library (http://ffmpeg.org/) as backend to record, convert and stream audio and video.
|
||||
FFmpeg is a complete, cross-reference solution. If you enable FFmpeg while configuring OpenCV than
|
||||
FFmpeg is a complete, cross-reference solution. If you enable FFmpeg while configuring OpenCV then
|
||||
CMake will download and install the binaries in `OPENCV_SOURCE_CODE/3rdparty/ffmpeg/`. To use
|
||||
FFmpeg at runtime, you must deploy the FFmpeg binaries with your application.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user