2012-04-06 23 views
16

Tôi muốn tìm lướt trên tất cả các hình ảnh trong một thư mục nhất định và lưu các điểm chính và mô tả của chúng để sử dụng trong tương lai. Tôi quyết định sử dụng dưa như hình dưới đây:Pickling cv2.KeyPoint gây PicklingError

#!/usr/bin/env python 
import os 
import pickle 
import cv2 

class Frame: 
    def __init__(self, filename): 
    surf = cv2.SURF(500, 4, 2, True) 
    self.filename = filename 
    self.keypoints, self.descriptors = surf.detect(cv2.imread(filename, cv2.CV_LOAD_IMAGE_GRAYSCALE), None, False) 

if __name__ == '__main__': 

    Fdb = open('db.dat', 'wb') 
    base_path = "img/" 
    frame_base = [] 

    for filename in os.listdir(base_path): 
    frame_base.append(Frame(base_path+filename)) 
    print filename 

    pickle.dump(frame_base,Fdb,-1) 

    Fdb.close() 

Khi tôi cố gắng thực hiện, tôi nhận được một lỗi sau:

File "src/pickle_test.py", line 23, in <module> 
    pickle.dump(frame_base,Fdb,-1) 
... 
pickle.PicklingError: Can't pickle <type 'cv2.KeyPoint'>: it's not the same object as cv2.KeyPoint 

Không ai biết, những gì nó có nghĩa và làm thế nào để sửa chữa nó? Tôi đang sử dụng Python 2.6 và OpenCV 2.3.1

Cảm ơn bạn rất nhiều

Trả lời

14

Vấn đề là bạn không thể đổ cv2.KeyPoint vào một tập tin dưa. Tôi đã có cùng một vấn đề, và quản lý để làm việc xung quanh nó bằng cách cơ bản serializing và deserializing các keypoints bản thân mình trước khi bán chúng với Pickle.

Vì vậy, đại diện cho tất cả các keypoint và mô tả của nó với một tuple:

temp = (point.pt, point.size, point.angle, point.response, point.octave, 
     point.class_id, desc)  

Nối tất cả những điểm này để một số danh sách mà bạn sau đó đổ với Pickle.

Sau đó, khi bạn muốn lấy lại dữ liệu, tải tất cả các dữ liệu với Pickle:

temp_feature = cv2.KeyPoint(x=point[0][0],y=point[0][1],_size=point[1], _angle=point[2], 
          _response=point[3], _octave=point[4], _class_id=point[5]) 
temp_descriptor = point[6] 

Tạo một cv2.KeyPoint từ dữ liệu này bằng cách sử dụng mã trên, và sau đó bạn có thể sử dụng những điểm này để xây dựng một danh sách các tính năng.

Tôi nghi ngờ có một cách neater để làm điều này, nhưng ở trên hoạt động tốt (và nhanh) cho tôi. Bạn có thể phải chơi xung quanh với định dạng dữ liệu của bạn một chút, vì các tính năng của tôi được lưu trữ trong danh sách định dạng cụ thể. Tôi đã cố gắng trình bày ở trên bằng cách sử dụng ý tưởng của tôi tại cơ sở chung của nó. Tôi hy vọng rằng điều này có thể giúp bạn.

0

Một phần của sự cố là cv2.KeyPoint là hàm trong python trả về đối tượng cv2.KeyPoint. Pickle đang bị nhầm lẫn bởi vì, theo nghĩa đen, "<type 'cv2.KeyPoint'> [là] not the same object as cv2.KeyPoint". Tức là, cv2.KeyPoint là đối tượng hàm, trong khi loại là cv2.KeyPoint. Tại sao OpenCV lại như thế, tôi chỉ có thể đoán trước khi tôi đi đào. Tôi có một cảm giác nó có một cái gì đó để làm với nó là một wrapper xung quanh một thư viện C/C++.

Python cung cấp cho bạn khả năng tự khắc phục sự cố này. I found the inspiration on this post about pickling methods of classes.

Tôi thực sự sử dụng đoạn mã này, cao biến đổi từ bản gốc trong bài

import copyreg 
import cv2 

def _pickle_keypoints(point): 
    return cv2.KeyPoint, (*point.pt, point.size, point.angle, 
          point.response, point.octave, point.class_id) 

copyreg.pickle(cv2.KeyPoint().__class__, _pickle_keypoints) 

Những điểm mấu chốt cần chú ý:

  • Trong Python 2, bạn cần phải sử dụng copy_reg thay vì copyreg .
  • Bạn không thể truy cập trực tiếp vào lớp cv2.KeyPoint vì một số lý do, vì vậy bạn tạo một đối tượng tạm thời và sử dụng nó.
  • Bản vá copyreg sẽ sử dụng chức năng cv2.KeyPoint khác có vấn đề như tôi đã chỉ định trong đầu ra của _pickle_keypoints khi tháo nút, vì vậy chúng tôi không cần triển khai quy trình làm trống.
  • Và để hoàn thành một cách nauseatingly, cv2::KeyPoint::KeyPoint là một hàm bị quá tải trong C++, nhưng trong Python, đây không phải là điều chính xác. Trong khi đó, trong C++, có một hàm lấy điểm cho đối số đầu tiên, bằng Python, nó sẽ cố gắng diễn giải nó như là một int thay thế. Các * bỏ ghi điểm thành hai đối số, xy để khớp với hàm tạo đối số duy nhất int.

Tôi đã sử dụng casper's excellent solution cho đến khi tôi nhận ra điều này là có thể.

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