mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
Merge pull request #29316 from pratham-mcw:dnn-arm64-neon-blobfromimages
dnn: optimize blobFromImages using NEON intrinsics on ARM64 #29316 - This PR optimizes the HWC-to-NCHW conversion in blobFromImages() by adding NEON implementation. - On x64, the MSVC compiler automatically vectorizes the existing scalar implementation, resulting in significantly better performance. - On Windows ARM64, MSVC does not auto-vectorize this stride-3 access pattern, leading to a noticeable performance gap compared to x64. - Added CV_NEON macro guard to ensure SIMD optimization is enabled on ARM64 architecture, leaving behavior on other platforms completely unchanged. **Performance Improvements** - This optimization significantly improves the performance of HWC-to-NCHW conversion on Windows ARM64. <img width="823" height="254" alt="image" src="https://github.com/user-attachments/assets/84b22deb-22da-4607-8009-3405c2529b80" /> - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [X] The PR is proposed to the proper branch
This commit is contained in:
@@ -152,29 +152,69 @@ void blobFromImagesNCHWImpl(const std::vector<Mat>& images, Mat& blob_, const Im
|
||||
if (param.swapRB)
|
||||
std::swap(p_blob_r, p_blob_b);
|
||||
|
||||
for (size_t i = 0; i < h; ++i)
|
||||
if (nch == 1)
|
||||
{
|
||||
const Tinp* p_img_row = images[k].ptr<Tinp>(i);
|
||||
|
||||
if (nch == 1)
|
||||
for (size_t i = 0; i < (size_t)h; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < w; ++j)
|
||||
const Tinp* p_img_row = images[k].ptr<Tinp>(i);
|
||||
for (size_t j = 0; j < (size_t)w; ++j)
|
||||
{
|
||||
p_blob[i * w + j] = p_img_row[j];
|
||||
}
|
||||
}
|
||||
else if (nch == 3)
|
||||
}
|
||||
else if (nch == 3)
|
||||
{
|
||||
if (images[k].isContinuous())
|
||||
{
|
||||
for (size_t j = 0; j < w; ++j)
|
||||
const Tinp* p_src = images[k].ptr<Tinp>();
|
||||
size_t i = 0;
|
||||
// NOTE: Visual Studio compiler is not able to vectorize the following loop on ARM64 CPU.
|
||||
// GCC and Clang does it efficiently.
|
||||
// TODO: Drop NEON block when MSVC is able to vectorize it too.
|
||||
#if CV_NEON
|
||||
if (sizeof(Tinp) == 4 && sizeof(Tout) == 4)
|
||||
{
|
||||
p_blob_r[i * w + j] = p_img_row[j * 3 ];
|
||||
p_blob_g[i * w + j] = p_img_row[j * 3 + 1];
|
||||
p_blob_b[i * w + j] = p_img_row[j * 3 + 2];
|
||||
const float* src_f = reinterpret_cast<const float*>(p_src);
|
||||
float* dst_r = reinterpret_cast<float*>(p_blob_r);
|
||||
float* dst_g = reinterpret_cast<float*>(p_blob_g);
|
||||
float* dst_b = reinterpret_cast<float*>(p_blob_b);
|
||||
for (; i + 4 <= (size_t)wh; i += 4)
|
||||
{
|
||||
float32x4x3_t rgb = vld3q_f32(src_f + i * 3);
|
||||
vst1q_f32(dst_r + i, rgb.val[0]);
|
||||
vst1q_f32(dst_g + i, rgb.val[1]);
|
||||
vst1q_f32(dst_b + i, rgb.val[2]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (; i < (size_t)wh; ++i)
|
||||
{
|
||||
p_blob_r[i] = p_src[i * 3 ];
|
||||
p_blob_g[i] = p_src[i * 3 + 1];
|
||||
p_blob_b[i] = p_src[i * 3 + 2];
|
||||
}
|
||||
}
|
||||
else // if (nch == 4)
|
||||
else
|
||||
{
|
||||
for (size_t j = 0; j < w; ++j)
|
||||
for (size_t i = 0; i < (size_t)h; ++i)
|
||||
{
|
||||
const Tinp* p_img_row = images[k].ptr<Tinp>(i);
|
||||
for (size_t j = 0; j < (size_t)w; ++j)
|
||||
{
|
||||
p_blob_r[i * w + j] = p_img_row[j * 3 ];
|
||||
p_blob_g[i * w + j] = p_img_row[j * 3 + 1];
|
||||
p_blob_b[i * w + j] = p_img_row[j * 3 + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // if (nch == 4)
|
||||
{
|
||||
for (size_t i = 0; i < (size_t)h; ++i)
|
||||
{
|
||||
const Tinp* p_img_row = images[k].ptr<Tinp>(i);
|
||||
for (size_t j = 0; j < (size_t)w; ++j)
|
||||
{
|
||||
p_blob_r[i * w + j] = p_img_row[j * 4 ];
|
||||
p_blob_g[i * w + j] = p_img_row[j * 4 + 1];
|
||||
|
||||
Reference in New Issue
Block a user