2012-07-07 47 views
17

Hiện tại tôi đang phát triển một số ứng dụng sử dụng API OpenCV (C++). Ứng dụng này xử lý với video.OpenCV: So sánh hiệu suất C++ và C

Trên PC mọi thứ hoạt động rất nhanh. Và hôm nay tôi quyết định chuyển ứng dụng này trên Android (để sử dụng máy ảnh như videoinput). May mắn thay, có OpenCV cho Android vì vậy tôi chỉ cần thêm mã nguồn gốc của tôi vào mẫu ứng dụng Android. Tất cả mọi thứ hoạt động tốt ngoại trừ sự hoàn hảo. Tôi điểm chuẩn ứng dụng của tôi và thấy rằng ứng dụng hoạt động với 4-5 fps, những gì thực sự là không thể chấp nhận được (thiết bị của tôi có bộ xử lý 1ghz singlecore) - Tôi muốn nó hoạt động với khoảng 10 khung hình/giây.

Liệu nó có tạo ra một sence để viết lại hoàn toàn ứng dụng của tôi trên C? Tôi biết rằng việc sử dụng những thứ như std::vector rất thoải mái cho nhà phát triển, nhưng tôi không quan tâm đến nó.

Dường như giao diện OpenCV's C có cùng chức năng/phương thức như giao diện C++.

Tôi googled câu hỏi này nhưng không tìm thấy gì cả.

Cảm ơn lời khuyên nào.

+3

Tôi không quen với Android nói riêng, nhưng việc sử dụng giao diện C của OpenCV không mang lại cho bạn hiệu suất đáng kể nào vì nó vẫn sử dụng cùng một mã cơ sở. – Mohammad

+0

Tôi đã thêm một số thông tin khác vào câu trả lời của tôi, hy vọng bạn sẽ thấy nó hữu ích. – Sam

Trả lời

53

Tôi đã làm việc khá nhiều với Android và tối ưu hóa (tôi đã viết một ứng dụng xử lý video xử lý khung trong 4ms) vì vậy tôi hy vọng tôi sẽ cung cấp cho bạn một số câu trả lời thích hợp.

Không có nhiều khác biệt giữa giao diện C và C++ trong OpenCV. Một số mã được viết bằng C, và có một trình bao bọc C++ và một số phó từ. Bất kỳ sự khác biệt đáng kể nào giữa hai (được đo bằng Shervin Emami) là hồi quy, sửa lỗi hoặc cải thiện chất lượng. Bạn nên gắn bó với phiên bản OpenCV mới nhất.

Tại sao không viết lại?

Bạn sẽ dành nhiều thời gian để sử dụng tốt hơn. Giao diện C là cồng kềnh, và cơ hội để giới thiệu lỗi hoặc rò rỉ bộ nhớ là cao. Bạn nên tránh nó, theo ý kiến ​​của tôi.

Lời khuyên dành cho tối ưu hóa

A. Bật tối ưu hóa.

Cả tối ưu hóa trình biên dịch và thiếu xác nhận gỡ lỗi có thể tạo sự khác biệt lớn trong thời gian chạy của bạn.

B. Hồ sơ ứng dụng của bạn.

Làm điều đó trước trên máy tính của bạn, vì nó dễ dàng hơn nhiều. Sử dụng profiler studio trực quan, để xác định các phần chậm. Tối ưu hóa chúng. Không bao giờ tối ưu hóa vì bạn nghĩ là chậm, nhưng vì bạn đo lường nó. Bắt đầu với chức năng chậm nhất, tối ưu hóa nó càng nhiều càng tốt, sau đó đi chậm thứ hai. Đo lường các thay đổi của bạn để đảm bảo rằng các thay đổi đó thực sự nhanh hơn.

C. Tập trung vào thuật toán.

Thuật toán nhanh hơn có thể cải thiện hiệu suất với các đơn đặt hàng có độ lớn (100x). Một thủ thuật C++ sẽ giúp bạn tăng hiệu năng gấp 2 lần.

kỹ thuật cổ điển:

  • Resize bạn khung hình video phải nhỏ hơn. Thông thường, bạn có thể trích xuất thông tin từ hình ảnh 200x300px thay vì 1024x768. Diện tích đầu tiên nhỏ hơn 10 lần.

  • Sử dụng các thao tác đơn giản hơn thay vì thao tác phức tạp. Sử dụng số nguyên thay vì phao. Và không bao giờ sử dụng double trong ma trận hoặc vòng lặp for thực thi hàng nghìn lần.

  • Làm càng ít phép tính càng tốt. Bạn có thể theo dõi một đối tượng chỉ trong một khu vực cụ thể của hình ảnh, thay vì xử lý tất cả đối tượng đó cho tất cả các khung hình không? Bạn có thể phát hiện thô/gần đúng trên một hình ảnh rất nhỏ và sau đó tinh chỉnh nó trên ROI trong toàn bộ khung hình không?

D. Sử dụng C mà nó quan trọng

Trong vòng, nó có thể làm cho tinh thần để sử dụng C phong cách thay vì C++. Một con trỏ tới một ma trận dữ liệu hoặc một mảng float nhanh hơn nhiều so với mat.at hoặc std :: vector <>. Thường thì nút cổ chai là một vòng lặp lồng nhau. Tập trung vào nó.Nó không có ý nghĩa để thay thế vector <> trên tất cả các nơi và spaghettify mã của bạn.

E. Tránh ẩn chi phí

Một số chức năng OpenCV chuyển đổi dữ liệu tăng gấp đôi, quá trình đó, sau đó chuyển đổi lại định dạng đầu vào. Cẩn thận với họ, họ giết hiệu suất trên các thiết bị di động. Ví dụ: cong vênh, mở rộng quy mô, nhập chuyển đổi. Ngoài ra, chuyển đổi không gian màu được biết là lười. Ưu tiên thang độ xám thu được trực tiếp từ YUV gốc.

F. Sử dụng vector hóa

vi xử lý ARM thực hiện vector hóa với một công nghệ gọi là NEON. Học cách sử dụng nó. Nó mạnh mẽ!

Một ví dụ nhỏ:

float* a, *b, *c; 
// init a and b to 1000001 elements 
for(int i=0;i<1000001;i++) 
    c[i] = a[i]*b[i]; 

thể được viết lại như sau. Đó là tiết, nhưng nhanh hơn nhiều.

float* a, *b, *c; 
// init a and b to 1000001 elements 
float32x4_t _a, _b, _c; 
int i; 
for(i=0;i<1000001;i+=4) 
{ 
    a_ = vld1q_f32(&a[i]); // load 4 floats from a in a NEON register 
    b_ = vld1q_f32(&b[i]); 
    c_ = vmulq_f32(a_, b_); // perform 4 float multiplies in parrallel 
    vst1q_f32(&c[i], c_); // store the four results in c 
} 
// the vector size is not always multiple of 4 or 8 or 16. 
// Process the remaining elements 
for(;i<1000001;i++) 
    c[i] = a[i]*b[i]; 

Purists say bạn phải viết trong trình biên dịch, nhưng đối với một lập trình viên thông thường thì hơi khó khăn. Tôi đã có kết quả tốt bằng cách sử dụng gcc intrinsics, như trong ví dụ trên.

Cách khác để bắt đầu là chuyển mã mã được tối ưu hóa SSE được mã hóa bằng tay trong OpenCV sang NEON. SSE tương đương với NEON trong bộ vi xử lý Intel và nhiều chức năng OpenCV sử dụng nó, như here. Đây là mã lọc hình ảnh cho ma trận uchar (định dạng hình ảnh thông thường). Bạn không nên chuyển đổi một cách mù quáng từng người một, nhưng lấy nó làm ví dụ để bắt đầu.

Bạn có thể đọc thêm về NEON trong this blog và các bài đăng sau.

G. Chú ý đến chụp ảnh

Nó có thể là đáng ngạc nhiên chậm trên một thiết bị di động. Tối ưu hóa nó là thiết bị và hệ điều hành cụ thể.

+0

Bạn có gợi ý về cách thăm dò ý kiến ​​của máy ảnh không? Sử dụng ví dụ của OpenCV 2.4.3.2 trên Nexus 4, nhận xét về bất kỳ quá trình xử lý nào, tôi chỉ thấy 10fps ở độ phân giải cao nhất, 20fps nếu tôi giảm xuống 176x144 .... –

+2

Không sử dụng API camera OpenCV. Chụp khung bằng API Java và chuyển chúng vào mã gốc. – Sam

+0

Cảm ơn! Tôi đã nghĩ tôi phải đi theo con đường đó, điều chỉnh những thứ tương tự như cách họ phải làm trong iOS. Bạn sẽ nghĩ rằng sẽ có ít nhất một ví dụ OpenCV phù hợp cho thông lượng ra khỏi bó .... –

4

Có một số bài kiểm tra hiệu suất do shervin imami thực hiện trên trang web của anh ấy. Bạn có thể kiểm tra nó để có được một số ý tưởng.

http://www.shervinemami.info/timingTests.html

Hy vọng điều đó sẽ hữu ích.

(Và cũng có thể, nó sẽ được tốt đẹp nếu bạn chia sẻ những phát hiện của riêng bạn ở đâu đó nếu bạn nhận được bất kỳ cách nào để tăng hiệu suất.)

+0

Cảm ơn bạn đã trả lời - Tôi sẽ xem xét bài kiểm tra đó và có thể tạo bài kiểm tra của riêng tôi. – ArtemStorozhuk

6

Trước khi thực hiện bất kỳ quyết định như thế này, bạn nên cấu hình mã của bạn để xác định vị trí các điểm nóng trong ma cua ban. Nếu không có thông tin này, bất kỳ thay đổi nào bạn thực hiện để tăng tốc độ mọi thứ sẽ là phỏng đoán. Bạn đã thử điều này Android NDK profiler?

+0

Cảm ơn bạn đã trả lời - Tôi sẽ thử. – ArtemStorozhuk

+2

@ Astor Và nếu điều đó không hiệu quả, bạn luôn có thể đi lừa cũ liên tục tạm dừng ứng dụng trong trình gỡ lỗi để có ý tưởng về nơi nó dành phần lớn thời gian của nó. –

3

Tôi đoán câu hỏi cần được xây dựng thành: C nhanh hơn C++? Và câu trả lời là không. Cả hai đều được biên dịch sang ngôn ngữ máy bản địa và C++ được thiết kế để nhanh như C Đối với STL (theo tiêu chuẩn ISO) cũng được thiết kế và chú ý rằng chúng nhanh như con trỏ + chúng cung cấp sự linh hoạt. Lý do duy nhất để sử dụng C là nền tảng của bạn không hỗ trợ C++ Trong lần mở khiêm tốn của tôi, không chuyển đổi mọi thứ thành C, vì bạn có thể sẽ đạt được hiệu suất gần như giống nhau. và thử thay vào đó để cải thiện mã của bạn hoặc sử dụng các chức năng khác của opencv để làm những gì bạn muốn.

Không thuyết phục? sau đó viết một hàm đơn giản, một lần trong C và một lần trong C++, và chạy nó trong vòng lặp 100 triệu lần và đo thời gian cho chính bạn. Có thể điều này giúp bạn đưa ra quyết định đúng

3

Tôi chưa bao giờ sử dụng C hoặc C++ trong Android. Nhưng trong PC, bạn có thể chạy C++ để chạy nhanh như mã C (đôi khi còn nhanh hơn). Hầu hết C++ được thiết kế đặc biệt để cho phép nhiều tính năng hơn, nhưng không phải với chi phí tốc độ (Mẫu được giải quyết tại thời gian biên dịch). Hầu hết các trình biên dịch là khá tốt để tối ưu hóa mã của bạn, và các lệnh std :: vector của bạn sẽ được nội tuyến và mã sẽ gần giống như sử dụng một mảng C nguyên gốc.

Tôi khuyên bạn nên tìm cách cải thiện hiệu suất của mình. Có thể có một số phần mở rộng phần cứng đa phương tiện trong Android bạn có thể truy cập và sử dụng để tối ưu hóa mã.

1

Tôi gặp sự cố tương tự trên thiết bị iOS và thảo luận Maximum speed from IOS/iPad/iPhone cũng bao gồm một số gợi ý áp dụng cho các nền tảng di động khác.

3

tôi nhận thấy trong nhiều bài kiểm tra mà:

  1. C giao diện (IplImage) là một số lần nhanh hơn khi truy cập vào các điểm ảnh trực tiếp thay vì sử dụng phương pháp Mat.at (x, y), khi tôi chuyển đổi ứng dụng C++ của tôi vào C, tôi có hiệu suất tăng gấp 3 lần trong các bước phát hiện blob của mình, thường có hiệu suất khi thực hiện các thói quen giống nhau trong C. Ví dụ về đây là FindContours và cvFindContours

  2. C tương thích hơn nhiều với các thiết bị nhúng. Tuy nhiên, tôi chưa làm gì trong lĩnh vực này.

Các vấn đề liên quan