2008-11-18 53 views
13

Cách tốt nhất để chia tỷ lệ mảng hình ảnh 2D là gì? Ví dụ: giả sử tôi có hình ảnh có kích thước 1024 x 2048 byte, với mỗi byte là pixel. Mỗi pixel là cấp độ thang độ xám từ 0 đến 255. Tôi muốn có thể chia tỷ lệ hình ảnh này theo một yếu tố tùy ý và nhận được hình ảnh mới. Vì vậy, nếu tôi chia tỷ lệ hình ảnh theo hệ số là 0,68, tôi sẽ nhận được hình ảnh có kích thước mới 0,68 * 1024 x 0,68 * 2048. một số điểm ảnh sẽ bị thu hẹp vào nhau. Và, nếu tôi mở rộng theo hệ số 3.15, tôi sẽ nhận được một hình ảnh lớn hơn với các pixel được nhân đôi. Vì vậy, cách tốt nhất để thực hiện điều này là gì?Chia tỷ lệ hình ảnh và xoay trong C/C++

Tiếp theo, tôi muốn có thể xoay hình ảnh theo một góc tùy ý, trong phạm vi từ 0 đến 360 độ (0 - 2Pi). Cắt ảnh sau khi xoay không phải là vấn đề. cách nào tốt nhất để làm việc này?

Trả lời

10

Không có cách "đơn giản" để làm điều đó. Cả tỷ lệ và xoay đều không phải là "trivial" procesis.

Google cho thư viện hình ảnh 2d. Magick++ có thể là một ý tưởng như điểm divideandconquer.se, nhưng có những điểm khác.

8

Bạn có muốn tự mình làm công việc dơ bẩn hoặc có thể ImageMagick làm điều đó cho bạn không?

12

Có nhiều cách để chia tỷ lệ và xoay hình ảnh. Cách đơn giản nhất để chia tỷ lệ là:

dest[dx,dy] = src[dx*src_width/dest_width,dy*src_height/dest_height] 

nhưng điều này tạo ra hiệu ứng khối khi tăng kích thước và mất chi tiết khi giảm kích thước. Có nhiều cách để tạo ra kết quả tìm kiếm tốt hơn, ví dụ: bilinear filtering.

Đối quay, vị trí src điểm ảnh có thể được tính bằng a rotation matrix:

sx,sy = M(dx,dy) 

trong đó M là một ma trận mà các bản đồ pixel đích để các hình ảnh nguồn. Một lần nữa, bạn sẽ cần phải làm nội suy để tạo ra kết quả không khối ô vuông.

Nhưng có rất nhiều thư viện có sẵn nếu bạn không muốn tham gia toán học về xử lý hình ảnh.

3

Sao chép hoặc loại bỏ pixel không phải là phương pháp hay thay đổi kích thước hình ảnh tốt nhất, vì kết quả sẽ hiển thị pixelation và jagginess. Để có kết quả tốt nhất, bạn nên resample hình ảnh, điều này sẽ mang lại cho hình ảnh kết quả trông mượt mà hơn nhiều. Có rất nhiều phương pháp để lấy mẫu lại, như bilinear, bicubic, lanczos, v.v.

Hãy xem hàm BicubicResample từ wxWidgets. Nó hoạt động sẽ tất cả các loại hình ảnh, không chỉ màu xám, nhưng bạn sẽ có thể thích ứng với nó theo nhu cầu của bạn. Sau đó, cũng có mã lấy mẫu from VirtualDub. Google Codesearch có thể tiết lộ nhiều mã liên quan hơn.

CHỈNH SỬA: các liên kết trông ổn trong bản xem trước nhưng bị hỏng khi được đăng. Điều này thật kỳ lạ. Đi tới tìm kiếm mã Google và truy vấn cho "wxwidgets resamplebicubic" và "virtualdub resample" tương ứng để có cùng kết quả.

9

Điều bạn đang làm là lập bản đồ một tập hợp các điểm đầu vào cho một tập hợp các điểm đầu ra. Phần đầu tiên của vấn đề là xác định ánh xạ để thay đổi kích thước hoặc xoay vòng của bạn; phần thứ hai là xử lý các điểm không nằm chính xác trên ranh giới pixel.

Mapping cho một thay đổi kích thước rất dễ dàng:

x' = x * (width'/width) 
y' = y * (height'/height) 

Mapping cho xoay chỉ là một chút khó khăn hơn.

x' = x * cos(a) + y * sin(a) 
y' = y * cos(a) - x * sin(a) 

Kỹ thuật xác định giá trị pixel nằm ngoài lưới được gọi là nội suy. Có rất nhiều thuật toán như vậy, khác nhau về tốc độ và chất lượng hình ảnh cuối cùng. Một vài trong số họ trong thứ tự ngày càng tăng của chất lượng/thời gian là hàng xóm gần nhất, bilinear, bicubic, và bộ lọc Sinc.

2

CxImage là thư viện miễn phí để xử lý hình ảnh, có thể làm những gì bạn muốn. Tôi chưa đích thân sử dụng nó ngoại trừ những thứ tầm thường, nhưng tôi đã thấy nó được đề xuất nhiều lần.

+0

Trong khi điều này về mặt lý thuyết có thể trả lời câu hỏi, [nó sẽ là thích hợp hơn] (// meta.stackoverflow .com/q/8259) để bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. –

0
point scaling(point p,float sx,float sy) { 
    point s; 

    int c[1][3]; 
    int a[1][3]={p.x,p.y,1}; 
    int b[3][3]={sx,0,0,0,sy,0,0,0,1}; 

    multmat(a,b,c); 

    s.x=c[0][0]; 
    s.y=c[0][1]; 

    return s; 
} 
0

Phương pháp thay đổi kích thước hình ảnh tạo ra kết quả lạ. Tôi đã sử dụng các hàm Resample và Resample2 với tất cả các biến thể có sẵn của các phương thức nội suy với cùng một kết quả. Ví dụ: thử đổi kích thước hình ảnh 1024 x 768 có màu trắng thành kích thước 802 x 582. Bạn sẽ thấy rằng có các pixel trên hình ảnh có màu khác nhau thành màu trắng! Bạn có thể kiểm tra điều này: mở hình ảnh đã thay đổi kích thước trong Windows Paint và thử tô nó bằng màu đen. Kết quả chắc chắn sẽ làm bạn hài lòng.

0

Khám phá Intel Performance Primitives. Tôi đã sử dụng nó trước đó và nó tạo ra hiệu suất tối ưu gần trên x86. Ngoài ra còn có một chương trình thử nghiệm cho phép chơi với các thuật toán khác nhau.

+0

Trong khi điều này về lý thuyết có thể trả lời câu hỏi, [nó sẽ là thích hợp hơn] (// meta.stackoverflow.com/q/8259) để bao gồm các phần thiết yếu của câu trả lời ở đây, và cung cấp liên kết để tham khảo. –

2

Nó chưa được đề cập đến, vì vậy tôi sẽ chỉ ra rằng OpenCV có các chức năng để mở rộng và xoay hình ảnh, cũng như một số lượng lớn các tiện ích khác. Nó có thể chứa nhiều tính năng không liên quan đến câu hỏi, nhưng rất dễ cài đặt và sử dụng cho một thư viện thuộc loại này.

Bạn có thể thử thực hiện các phép biến đổi như thế này theo cách thủ công, nhưng cách tiếp cận đơn giản để chia tỷ lệ và xoay sẽ thường dẫn đến mất chi tiết đáng kể.

Sử dụng OpenCV, mở rộng quy mô có thể được thực hiện như sau:

float scaleFactor = 0.68f; 
cv::Mat original = cv::imread(path); 
cv::Mat scaled; 
cv::resize(original, scaled, cv::Size(0, 0), scaleFactor, scaleFactor, cv::INTER_LANCZOS4); 
cv::imwrite("new_image.jpg", scaled); 

này quy mô hình ảnh xuống bởi một yếu tố của 0,68 sử dụng Lanczos suy.

Tôi không quen thuộc với xoay vòng, nhưng đây là một phần của ví dụ từ một trong các hướng dẫn trên trang web OpenCV mà tôi đã chỉnh sửa xuống các phần liên quan. (Bản gốc đã nghiêng và dịch trong nó cũng ...)

/// Compute a rotation matrix with respect to the center of the image 
Point center = Point(original.size().width/2, original.size().height/2); 
double angle = -50.0; 
double scale = 0.6; 

/// Get the rotation matrix with the specifications above 
Mat rot_mat(2, 3, CV_32FC1); 
rot_mat = getRotationMatrix2D(center, angle, scale); 

/// Rotate the image 
Mat rotated_image; 
warpAffine(src, rotated_image, rot_mat, src.size()); 

OpenCV Website

They have some very nice documentation too.

+0

Điểm tốt. Tôi đã thêm một số ví dụ để bây giờ nó là một câu trả lời thực sự hơn. – Meta

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