Uzun süredir nümerik hesaplarım için IPython kabuğu ile Python’ın numpy modülünü kullanıyorum ve çok memnunum. Hele Opencv’nin güzel sürümündeki (svn’deki sürümü oluyor) matris yapısını numpy dizisine (ndarray) çevirebilince işlem kolaylığı ve çokluğu arttı, daha da şık oldu.
Bunun ne faydası var konusunda bir fikir vereyim. Opencv, içinde birçok bilgisayarla görme algoritmasını barındıran muhteşem bir açık kaynak kütüphane. Numpy, Matlab’ın Python muadili. Numpy neredeyse standart oldu ve tüm nümerik kütüphaneler onu destekliyor. Benim kullandığım en temel kütüphaneler grafik kütüphaneleri (matplotlib gibi) de Numpy destekli. Numpy’ın en güçlü yanı, dilimleme (“slicing”) operatörü. Matlab kullananlar bunu bilir ve sever. Ayrıca işleri vektörlemek de mümkün. Kullanımı çok esnek. Opencv’de hazır fonksiyonları kullanmak çok kolay ama resimlerden istatistik falan toplayacaksanız işiniz Numpy sözdiziminde olduğu kadar kolay değil. Böyle bir çevirme işlemiyle ikisinin gücü birleşiyor. Bu arada, tüm bahsettiğim kütüphaneler platformdan bağımsız.
Şu anlık yalnızca float32 ve uint8 veri türlerini çevirdim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def opencv2numpy(matIn): """Convert opencv matrix to numpy matrix (supports 1 and 3 channels currently)""" if matIn[0].type == cv.CV_8UC1 or matIn[0].type == cv.CV_8UC3: dtype = 'uint8' elif matIn[0].type == cv.CV_32FC1 or matIn[0].type == cv.CV_32FC3: dtype = 'float32' else: print "No support except float32 and uint8 yet" return 0 if matIn[0].type == cv.CV_8UC3 or matIn[0].type == cv.CV_32FC3: matOut = np.fromstring(matIn.tostring(), dtype=dtype).reshape(matIn.height, matIn.width, 3) else: matOut = np.fromstring(matIn.tostring(), dtype=dtype).reshape(matIn.height, matIn.width) return matOut |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | def numpy2opencv(matIn): if matIn.ndim == 3 and matIn.shape[2] == 3: nChannels = 3 else: nChannels = 1 h,w = matIn.shape[0], matIn.shape[1] if matIn.dtype == "uint8": if nChannels == 1: dtype = cv.CV_8UC1 else: dtype = cv.CV_8UC3 elif matIn.dtype == "float32": if nChannels == 1: dtype = cv.CV_32FC1 else: dtype = cv.CV_32FC3 else: print "No support except float32 and uint8 yet" return 0 matOut = cv.CreateMatHeader(h, w, dtype) if nChannels == 1: cv.SetData(matOut, matIn.data, w*matIn.itemsize) else: cv.SetData(matOut, matIn.data, w*4*matIn.itemsize) return matOut |
Güncel işimi görmesi için yazdığımdan hataları olabilir, biraz da verimsiz oldu. Örneğin bir tarafa iyiyken, diğer tarafa verimsiz çeviriyor. Fakat benim için şu an bu öncelik konusu değil. “Exception” fırlatmam lazım ama hariçten gazel okumak zor geldi, işimi görüyor.
Kullanırsanız, genellerseniz veya geliştirirseniz lütfen benimle de paylaşın.
Güncelleme:
Opencv Python arayüzünde zaten hazırmış bu kod. Hem diğer veritipleri için de genellenmiş. Yenisi dönüşümler şöyle:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | def cv2array(im): depth2dtype = { cv.IPL_DEPTH_8U: 'uint8', cv.IPL_DEPTH_8S: 'int8', cv.IPL_DEPTH_16U: 'uint16', cv.IPL_DEPTH_16S: 'int16', cv.IPL_DEPTH_32S: 'int32', cv.IPL_DEPTH_32F: 'float32', cv.IPL_DEPTH_64F: 'float64', } arrdtype=im.depth a = np.fromstring( im.tostring(), dtype=depth2dtype[im.depth], count=im.width*im.height*im.nChannels) a.shape = (im.height,im.width,im.nChannels) return a def array2cv(a): dtype2depth = { 'uint8': cv.IPL_DEPTH_8U, 'int8': cv.IPL_DEPTH_8S, 'uint16': cv.IPL_DEPTH_16U, 'int16': cv.IPL_DEPTH_16S, 'int32': cv.IPL_DEPTH_32S, 'float32': cv.IPL_DEPTH_32F, 'float64': cv.IPL_DEPTH_64F, } try: nChannels = a.shape[2] except: nChannels = 1 cv_im = cv.CreateImageHeader((a.shape[1], a.shape[0]), dtype2depth[str(a.dtype)], nChannels) cv.SetData(cv_im, a.tostring(), a.dtype.itemsize*nChannels*a.shape[1]) return cv_im |