2011-06-29 33 views
9

Tôi có một hình ảnh màn hình khá lớn, gần như đầy đủ mà tôi sẽ hiển thị trên iPad. Hình ảnh có độ trong suốt khoảng 80%. Tôi cần phải, trên máy khách, xác định hộp giới hạn của các điểm ảnh mờ đục, và sau đó cắt đến hộp giới hạn đó.Cắt UIImage thành alpha

quét các câu hỏi khác ở đây trên StackOverflow và đọc một số tài liệu CoreGraphics, tôi nghĩ rằng tôi có thể thực hiện điều này bằng cách:

CGBitmapContextCreate(...) // Use this to render the image to a byte array 

.. 
    - iterate through this byte array to find the bounding box 
.. 

CGImageCreateWithImageInRect(image, boundingRect); 

Đó chỉ có vẻ rất không hiệu quả và khá cồng kềnh. Có một cái gì đó thông minh tôi có thể làm với mặt nạ CGImage hoặc một cái gì đó mà làm cho việc sử dụng tăng tốc đồ họa của thiết bị để làm điều này?

+0

Bạn đã thử thiết bị này trên thiết bị chưa? Tôi đặt cược nó sẽ nhanh hơn bạn nghĩ. –

+0

Sự thật của nó - một khi tôi thực sự ngồi xuống và thực hiện nó, thời gian xử lý nhanh hơn nhiều so với tôi nghĩ rằng nó sẽ được! – MikeQ

Trả lời

0

Không có gian lận thông minh để làm việc với thiết bị, nhưng có một số cách để tăng tốc tác vụ hoặc giảm thiểu tác động trên giao diện người dùng.

Trước tiên, hãy xem xét sự cần thiết phải đẩy nhanh nhiệm vụ này. Một phép lặp đơn giản thông qua mảng byte này có thể đủ nhanh. Có thể không cần phải đầu tư vào việc tối ưu hóa tác vụ này nếu ứng dụng chỉ tính toán một lần cho mỗi lần chạy hoặc phản ứng với lựa chọn của người dùng mất ít nhất vài giây giữa các lựa chọn.

Nếu không cần hộp giới hạn trong một thời gian sau khi hình ảnh khả dụng, lần lặp này có thể được khởi chạy trong một chuỗi riêng biệt. Bằng cách đó, tính toán không chặn luồng giao diện chính. Grand Central Dispatch có thể sử dụng một sợi riêng biệt cho nhiệm vụ này dễ dàng hơn.

Nếu tác vụ phải được tăng tốc, có thể đây là xử lý thời gian thực của hình ảnh video, sau đó xử lý song song dữ liệu có thể hữu ích. Khung tăng tốc có thể giúp thiết lập tính toán SIMD trên dữ liệu. Hoặc, để thực sự có được hiệu suất với lần lặp này, mã ngôn ngữ lắp ráp ARM sử dụng các hoạt động SIMON NEON có thể nhận được kết quả tuyệt vời với nỗ lực phát triển đáng kể.

Lựa chọn cuối cùng là điều tra thuật toán tốt hơn. Có một lượng lớn công việc phát hiện các tính năng trong hình ảnh. Thuật toán phát hiện cạnh có thể nhanh hơn một phép lặp đơn giản thông qua mảng byte. Có lẽ Apple sẽ bổ sung khả năng phát hiện cạnh vào Core Graphics trong tương lai có thể áp dụng cho trường hợp này. Apple đã triển khai khả năng xử lý hình ảnh có thể không phù hợp chính xác cho trường hợp này, nhưng việc triển khai của Apple cần được tối ưu hóa để sử dụng khả năng của SIMD hoặc GPU của iPad, dẫn đến hiệu suất tổng thể tốt hơn.

8

Tôi tạo ra một thể loại trên UImage mà thực hiện điều này nếu có ai cần nó ...

+ (UIImage *)cropTransparencyFromImage:(UIImage *)img { 

    CGImageRef inImage = img.CGImage;   
    CFDataRef m_DataRef; 
    m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage)); 
    UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef); 

    int width = img.size.width; 
    int height = img.size.height; 

    CGPoint top,left,right,bottom; 

    BOOL breakOut = NO; 
    for (int x = 0;breakOut==NO && x < width; x++) { 
     for (int y = 0; y < height; y++) { 
      int loc = x + (y * width); 
      loc *= 4; 
      if (m_PixelBuf[loc + 3] != 0) { 
       left = CGPointMake(x, y); 
       breakOut = YES; 
       break; 
      } 
     } 
    } 

    breakOut = NO; 
    for (int y = 0;breakOut==NO && y < height; y++) { 

     for (int x = 0; x < width; x++) { 

      int loc = x + (y * width); 
      loc *= 4; 
      if (m_PixelBuf[loc + 3] != 0) { 
       top = CGPointMake(x, y); 
       breakOut = YES; 
       break; 
      } 

     } 
    } 

    breakOut = NO; 
    for (int y = height-1;breakOut==NO && y >= 0; y--) { 

     for (int x = width-1; x >= 0; x--) { 

      int loc = x + (y * width); 
      loc *= 4; 
      if (m_PixelBuf[loc + 3] != 0) { 
       bottom = CGPointMake(x, y); 
       breakOut = YES; 
       break; 
      } 

     } 
    } 

    breakOut = NO; 
    for (int x = width-1;breakOut==NO && x >= 0; x--) { 

     for (int y = height-1; y >= 0; y--) { 

      int loc = x + (y * width); 
      loc *= 4; 
      if (m_PixelBuf[loc + 3] != 0) { 
       right = CGPointMake(x, y); 
       breakOut = YES; 
       break; 
      } 

     } 
    } 


    CGRect cropRect = CGRectMake(left.x, top.y, right.x - left.x, bottom.y - top.y); 

    UIGraphicsBeginImageContextWithOptions(cropRect.size, 
              NO, 
              0.); 
    [img drawAtPoint:CGPointMake(-cropRect.origin.x, -cropRect.origin.y) 
      blendMode:kCGBlendModeCopy 
       alpha:1.]; 
    UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return croppedImage; 
} 
+1

Cảm ơn kịch bản này. Tôi sử dụng nó trong dự án của tôi, nhưng tôi nhận thấy một vấn đề rò rỉ bộ nhớ. Tôi nghĩ chúng ta cần gọi là "CFRelease (m_DataRef);" trước "return croppedImage;" –

+0

Cảm ơn người dùng phản hồi hữu ích đó. Bạn có biết nếu có một cách, sau khi bạn đã lấy các điểm để áp dụng một biến đổi cho họ? –

+0

Chỉ cần lặp lại nhận xét của tôi trong trường hợp người khác đang xem: Tôi vừa mới triển khai điều này trong chương trình của mình - đó chính xác là những gì tôi cần! Nhưng tôi nhận được và EXC_BAD_ACCESS trên đầu tiên nếu (m_PixelBuf [loc + 3]! = 0) {line. Bất kỳ ý tưởng tại sao?Cảm ơn – Smikey

13

Nhờ user404709 để làm tất cả các công việc khó khăn. Mã dưới đây cũng xử lý hình ảnh võng mạc và giải phóng CFDataRef.

- (UIImage *)trimmedImage { 

    CGImageRef inImage = self.CGImage; 
    CFDataRef m_DataRef; 
    m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage)); 

    UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef); 

    size_t width = CGImageGetWidth(inImage); 
    size_t height = CGImageGetHeight(inImage); 

    CGPoint top,left,right,bottom; 

    BOOL breakOut = NO; 
    for (int x = 0;breakOut==NO && x < width; x++) { 
     for (int y = 0; y < height; y++) { 
      int loc = x + (y * width); 
      loc *= 4; 
      if (m_PixelBuf[loc + 3] != 0) { 
       left = CGPointMake(x, y); 
       breakOut = YES; 
       break; 
      } 
     } 
    } 

    breakOut = NO; 
    for (int y = 0;breakOut==NO && y < height; y++) { 

     for (int x = 0; x < width; x++) { 

      int loc = x + (y * width); 
      loc *= 4; 
      if (m_PixelBuf[loc + 3] != 0) { 
       top = CGPointMake(x, y); 
       breakOut = YES; 
       break; 
      } 

     } 
    } 

    breakOut = NO; 
    for (int y = height-1;breakOut==NO && y >= 0; y--) { 

     for (int x = width-1; x >= 0; x--) { 

      int loc = x + (y * width); 
      loc *= 4; 
      if (m_PixelBuf[loc + 3] != 0) { 
       bottom = CGPointMake(x, y); 
       breakOut = YES; 
       break; 
      } 

     } 
    } 

    breakOut = NO; 
    for (int x = width-1;breakOut==NO && x >= 0; x--) { 

     for (int y = height-1; y >= 0; y--) { 

      int loc = x + (y * width); 
      loc *= 4; 
      if (m_PixelBuf[loc + 3] != 0) { 
       right = CGPointMake(x, y); 
       breakOut = YES; 
       break; 
      } 

     } 
    } 


    CGFloat scale = self.scale; 

    CGRect cropRect = CGRectMake(left.x/scale, top.y/scale, (right.x - left.x)/scale, (bottom.y - top.y)/scale); 
    UIGraphicsBeginImageContextWithOptions(cropRect.size, 
              NO, 
              scale); 
    [self drawAtPoint:CGPointMake(-cropRect.origin.x, -cropRect.origin.y) 
      blendMode:kCGBlendModeCopy 
       alpha:1.]; 
    UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    CFRelease(m_DataRef); 
    return croppedImage; 
} 
+0

Tôi vừa mới thực hiện điều này trong chương trình của mình - đó chính xác là những gì tôi cần! Nhưng tôi nhận được và EXC_BAD_ACCESS trên đầu tiên nếu (m_PixelBuf [loc + 3]! = 0) { dòng. Bất kỳ ý tưởng tại sao? Cảm ơn. – Smikey

+0

@Smikey, đang cố gắng sử dụng điều này trên một hình ảnh được chụp từ máy ảnh? Nếu vậy, theo [http://stackoverflow.com/a/12614015/1541893] này bởi user1702121, "' CGBitmapContextGetData() 'trên ngữ cảnh được tạo từ một bộ đệm mẫu đã capture không trả lại bitmap". Anh ấy cung cấp một giải pháp. – Dan

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