Python ve OpenCV Kullanarak Gerçek Zamanlı Nesne Ölçümü
Bu derste OpenCV ve Python kullanarak nesne ölçümünün nasıl yapılacağını öğreneceğiz. Rehberimiz olarak bir A4 kağıt kullanacağız ve bu bölgeye yerleştirilen nesnelerin genişliğini ve yüksekliğini bulacağız.
İçerik Tablosu
Kodlama
Kütüphaneleri Dahil Etme
Kütüphanelerimizi ithal ederek başlayacağız. Şimdi ObjectMeasurement.py adında bir ana komut dosyası ve tüm yardım fonksiyonlarımızı yazmak için utlis.py bir yardımcı program komut dosyası kullanacağız . Opencv ve numpy paketlerini kuracağız ve daha sonra komut dosyalarımıza aktaracağız.
Ana Script
import cv2 import utlis
Araçlar
import cv2 import numpy as np
Görüntü ve Web Kamerası
Öğreticinin çoğu için görüntüye sadık kalacağız ve en sonunda bir web kamerasına geçeceğiz. Bu, süreci biraz daha yönetilebilir hale getirir. Şimdi elimizdeki görüntü büyük, bu yüzden onu görebilmemiz için en sonunda azaltacağız. Gerçekte, hesaplamalar gerçek görüntü boyutu kullanılarak yapılacaktır.
Web kamerası ve görüntü dosyasından mesafe ölçümü arasında seçim yapabilmek amacıyla webcam adında bir değişken tanımladık. Bu değişken False değerinde ise görüntü dosyası True değeri alırsa da WebCam’den mesafe ölçümü yapılır.Kamera varsayılan olarak 0 yani bilgisayarınızın ana kamerasını açar. Farklı bir kamera kullanmak için bu değeri değiştirebiirsiniz.
webcam = False path = '1.jpg' cap = cv2.VideoCapture(0) cap.set(10,160) cap.set(3,1920) cap.set(4,1080) while True: if webcam:success,img = cap.read() else: img = cv2.imread(path) img = cv2.resize(img,(0,0),None,0.5,0.5) cv2.imshow('Original',img) cv2.waitKey(1)
Contours Fonksiyonu
Şimdi önce A4 kağıdını bulmamıza ve daha sonra içindeki nesneyi bulmamıza izin veren bir contours fonksiyonu yaratacağız. Bu nedenle, her iki görevi yerine getirmek için aynı işlevi kullanacağız. Bu işlevselliği önceki birçok öğreticide kullandık (Şekil Algılama Uygulamasına Bakabilirsiniz) , ancak bunun için gerçekten genel bir işlev oluşturmadık. Bu yüzden, birden fazla projede kullanabileceğimiz bir fonksiyon yarattık.
Burada fikir basitçe renkli görüntüler gönderiyoruz ve bize tüm nesne bilgilerini içeren bir liste döndürüyor. Bu yüzden önce renkli imajımıza bazı önermeler uygulayacağız. Gri skalaya dönüştüreceğiz, sonra biraz bulanıklık ekleyeceğiz, sonra Canny kenar dedektörünü kullanarak kenarları bulacağız ve daha sonra biraz genişleme ve erozyon uygulayacağız. Canny işlevi 2 eşik aldığından, kullanıcının değiştirmek istediği takdirde bunu kontur fonksiyonlarımız için bir argüman olarak koyacağız. Ayrıca, canny görüntüsünü görüntülemek için bir değişken ekleyeceğiz.
def getContours(img,cThr=[100,100],showCanny=False,minArea=1000,filter=0,draw =False): imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) imgBlur = cv2.GaussianBlur(imgGray,(5,5),1) imgCanny = cv2.Canny(imgBlur,cThr[0],cThr[1]) kernel = np.ones((5,5)) imgDial = cv2.dilate(imgCanny,kernel,iterations=3) imgThre = cv2.erode(imgDial,kernel,iterations=2) if showCanny:cv2.imshow('Canny',imgThre)
Görüntüyü hazır hale getirdikten sonra artık cv2 findCountours işlevine gönderebiliriz. Burada Dış yöntemi kullanacağız, bu nedenle basit kontur yaklaşımıyla birlikte dış konturları bulacağız. Şimdi tespit edilen tüm konturlar arasında dolaşabilir ve alanlarını bulabiliriz. Bu, Alan Filtresi eklememize izin verecektir. Bunu fonksiyonumuza girdi olarak da koyacağız. Minimum alan filtresi gürültüyü önlememizi sağlar. Daha sonra her bir konturun sahip olduğu köşe sayısına yaklaşacağız ve üzerine bir filtre uygulayacağız. Bu, örneğin yalnızca kare nesneler veya üçgen nesneler yerine hepsinden ziyade belirli bir şekil istememiz durumunda eklenir. Son olarak, tüm bu bilgileri bir listeye koyacağız ve en büyük konturun önce gelmesi için yeniden sıralayacağız.
contours,hiearchy = cv2.findContours(imgThre,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) finalCountours = [] for i in contours: area = cv2.contourArea(i) if area > minArea: peri = cv2.arcLength(i,True) approx = cv2.approxPolyDP(i,0.02*peri,True) bbox = cv2.boundingRect(approx) if filter > 0: if len(approx) == filter: finalCountours.append([len(approx),area,approx,bbox,i]) else: finalCountours.append([len(approx),area,approx,bbox,i]) finalCountours = sorted(finalCountours,key = lambda x:x[1] ,reverse= True)
Geliştirme süreci için yöntemimizi değerlendirmek üzere bir görüntüleme işlevselliğine sahip olmak esastır. Bu yüzden, giriş görüntüsünde son konturları çizecek bir ekran bayrağı da ekleyeceğiz.
if draw: for con in finalCountours: cv2.drawContours(img,con[4],-1,(0,0,255),3) return img, finalCountours
Artık A4 kağıt bulmak için ana komut dosyamızda bu işlevi çağırabiliriz. Kağıdın dört köşesi olduğundan 4 filtre değerini ve 50.000 min alan büyüklüğünü ekleyeceğiz. Kontür listesine geri döndüğümüzde, ilk öğeyi basitçe azalan düzende çıkararak çıkarabiliriz. Bazen konturlar bulunmaz ve listemizden elementi çıkarmaya çalışırsak hata verir. Bundan kaçınmak için önce listenin boş olmadığını kontrol edip devam edeceğiz.
imgContours , conts = utlis.getContours(img,minArea=50000,filter=4) if len(conts) != 0: biggest = conts[0][2] #print(biggest)
ReOrder fonksiyonu
Şimdi A4 kağıdımızın köşe noktalarına sahip olduğumuza göre, bükülmemiz gerekiyor, böylece yöndeki herhangi bir eğim sabitleşiyor. Ancak görüntüyü çarpıtmak için, köşe noktalarını her elde ettiğimizde emin olmalıyız. Bundan emin olmak için köşe noktalarını alan bir yeniden sıralama işlevi oluşturacağız ve bunları yeniden sıralayacağız.
def reorder(myPoints): #print(myPoints.shape) myPointsNew = np.zeros_like(myPoints) myPoints = myPoints.reshape((4,2)) add = myPoints.sum(1) myPointsNew[0] = myPoints[np.argmin(add)] myPointsNew[3] = myPoints[np.argmax(add)] diff = np.diff(myPoints,axis=1) myPointsNew[1]= myPoints[np.argmin(diff)] myPointsNew[2] = myPoints[np.argmax(diff)] return myPointsNew
Şimdi yeniden sıralanan noktaları kullanarak yeni çarpık görüntülerimizi oluşturabiliriz. Noktaları hazırlayacağız ve dönüşüm matrisini yaratacağız. Sonra bunu Çözgü Perspektifi fonksiyonuna gireceğiz. Sonuç 100 kağıt olmadığı için kenarlara biraz dolgu ekleyebiliriz.
def warpImg (img,points,w,h,pad=20): # print(points) points =reorder(points) pts1 = np.float32(points) pts2 = np.float32([[0,0],[w,0],[0,h],[w,h]]) matrix = cv2.getPerspectiveTransform(pts1,pts2) imgWarp = cv2.warpPerspective(img,matrix,(w,h)) imgWarp = imgWarp[pad:imgWarp.shape[0]-pad,pad:imgWarp.shape[1]-pad] return imgWarp
Şimdi bu işlevi çağırabiliriz
imgWarp = utlis.warpImg(img, biggest, wP,hP)
Nesne Ölçümü
Çarpık görüntüyü kullanarak nesnelerimizin konturlarını bulacağız.
imgContours2, conts2 = utlis.getContours(imgWarp, minArea=2000, filter=4, cThr=[50,50],draw = False)
Kontürlerin ve sınırlayıcı kutularının bir listesine sahip olduğumuz göz önüne alındığında, şimdi konturlarımızın genişliğini ve yüksekliğini bulabiliriz. Ancak buradaki sorun, sınırlayıcı kutumuzun genişliğini ve yüksekliğini alabilmemiz için nesnenin yatırılabilmesidir. Büyüklüğü 2 nokta ve biraz matematik kullanarak bulabiliriz.
def findDis(pts1,pts2): return ((pts2[0]-pts1[0])**2 + (pts2[1]-pts1[1])**2)**0.5 if len(conts) != 0: for obj in conts2: cv2.polylines(imgContours2,[obj[2]],True,(0,255,0),2) nPoints = utlis.reorder(obj[2]) nW = round((utlis.findDis(nPoints[0][0]//scale,nPoints[1][0]//scale)/10),1) nH = round((utlis.findDis(nPoints[0][0]//scale,nPoints[2][0]//scale)/10),1)
Görüntüleme
Son olarak, nesne ölçümlerimizi bazı oklarla birlikte görüntüleyebiliriz.
cv2.arrowedLine(imgContours2, (nPoints[0][0][0], nPoints[0][0][1]), (nPoints[1][0][0], nPoints[1][0][1]), (255, 0, 255), 3, 8, 0, 0.05) cv2.arrowedLine(imgContours2, (nPoints[0][0][0], nPoints[0][0][1]), (nPoints[2][0][0], nPoints[2][0][1]), (255, 0, 255), 3, 8, 0, 0.05) x, y, w, h = obj[3] cv2.putText(imgContours2, '{}cm'.format(nW), (x + 30, y - 10), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.5,(255, 0, 255), 2) cv2.putText(imgContours2, '{}cm'.format(nH), (x - 70, y + h // 2), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.5,(255, 0, 255), 2) cv2.imshow('A4', imgContours2)
Komple Kod
Nesne Ölçümü.py
import cv2 import utlis ################################### webcam = True path = '1.jpg' cap = cv2.VideoCapture(0) cap.set(10,160) cap.set(3,1920) cap.set(4,1080) scale = 3 wP = 210 *scale hP= 297 *scale ################################### while True: if webcam:success,img = cap.read() else: img = cv2.imread(path) imgContours , conts = utlis.getContours(img,minArea=50000,filter=4) if len(conts) != 0: biggest = conts[0][2] #print(biggest) imgWarp = utlis.warpImg(img, biggest, wP,hP) imgContours2, conts2 = utlis.getContours(imgWarp, minArea=2000, filter=4, cThr=[50,50],draw = False) if len(conts) != 0: for obj in conts2: cv2.polylines(imgContours2,[obj[2]],True,(0,255,0),2) nPoints = utlis.reorder(obj[2]) nW = round((utlis.findDis(nPoints[0][0]//scale,nPoints[1][0]//scale)/10),1) nH = round((utlis.findDis(nPoints[0][0]//scale,nPoints[2][0]//scale)/10),1) cv2.arrowedLine(imgContours2, (nPoints[0][0][0], nPoints[0][0][1]), (nPoints[1][0][0], nPoints[1][0][1]), (255, 0, 255), 3, 8, 0, 0.05) cv2.arrowedLine(imgContours2, (nPoints[0][0][0], nPoints[0][0][1]), (nPoints[2][0][0], nPoints[2][0][1]), (255, 0, 255), 3, 8, 0, 0.05) x, y, w, h = obj[3] cv2.putText(imgContours2, '{}cm'.format(nW), (x + 30, y - 10), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.5, (255, 0, 255), 2) cv2.putText(imgContours2, '{}cm'.format(nH), (x - 70, y + h // 2), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.5, (255, 0, 255), 2) cv2.imshow('A4', imgContours2) img = cv2.resize(img,(0,0),None,0.5,0.5) cv2.imshow('Original',img) cv2.waitKey(1)
Utlis.py
import cv2 import numpy as np def getContours(img,cThr=[100,100],showCanny=False,minArea=1000,filter=0,draw =False): imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) imgBlur = cv2.GaussianBlur(imgGray,(5,5),1) imgCanny = cv2.Canny(imgBlur,cThr[0],cThr[1]) kernel = np.ones((5,5)) imgDial = cv2.dilate(imgCanny,kernel,iterations=3) imgThre = cv2.erode(imgDial,kernel,iterations=2) if showCanny:cv2.imshow('Canny',imgThre) contours,hiearchy = cv2.findContours(imgThre,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) finalCountours = [] for i in contours: area = cv2.contourArea(i) if area > minArea: peri = cv2.arcLength(i,True) approx = cv2.approxPolyDP(i,0.02*peri,True) bbox = cv2.boundingRect(approx) if filter > 0: if len(approx) == filter: finalCountours.append([len(approx),area,approx,bbox,i]) else: finalCountours.append([len(approx),area,approx,bbox,i]) finalCountours = sorted(finalCountours,key = lambda x:x[1] ,reverse= True) if draw: for con in finalCountours: cv2.drawContours(img,con[4],-1,(0,0,255),3) return img, finalCountours def reorder(myPoints): #print(myPoints.shape) myPointsNew = np.zeros_like(myPoints) myPoints = myPoints.reshape((4,2)) add = myPoints.sum(1) myPointsNew[0] = myPoints[np.argmin(add)] myPointsNew[3] = myPoints[np.argmax(add)] diff = np.diff(myPoints,axis=1) myPointsNew[1]= myPoints[np.argmin(diff)] myPointsNew[2] = myPoints[np.argmax(diff)] return myPointsNew def warpImg (img,points,w,h,pad=20): # print(points) points =reorder(points) pts1 = np.float32(points) pts2 = np.float32([[0,0],[w,0],[0,h],[w,h]]) matrix = cv2.getPerspectiveTransform(pts1,pts2) imgWarp = cv2.warpPerspective(img,matrix,(w,h)) imgWarp = imgWarp[pad:imgWarp.shape[0]-pad,pad:imgWarp.shape[1]-pad] return imgWarp def findDis(pts1,pts2): return ((pts2[0]-pts1[0])**2 + (pts2[1]-pts1[1])**2)**0.5
Video öğretici
Son Sözler
Sitemizde OpenCV ile ilgili birçok örnek uygulamaya erişebilirsiniz. Bu yazının orijinal haline murtazahassan.com sitesinden erişebilirsiniz.
Yorumlarınızı bekliyorum.
hocam çok kral çalışmalar yapmışsınız ellerinize saglik cok güzel calisiyor program
boy, en ve ağırlık nasıl belirlenir
bir kavunun en boy ve ağırlığı bilinirse onun daha sonra diğer kavunlar için ağırlık tahmini nasıl yaparız
derin öğrenme cnn ile kastediyorum
hiç bir yerde bununla ilgili bir kod bulamadım
yardımcı olabilir misiniz
Onunla ilgili başka kaynaklara bakmalısınız. Derin öğrenme ile olur ancak örnek kod olarak benzer çalışmalar varsa bakılabilir.
Merhabalar kodları çalıştırıyorum ancak ölçüm yapılan ekran açılmıyor orjinali görüyorum sadece. sebei konusunda bilginiz var mı acaba? şimdiden teşekkür ederim.
Videoda 1.34 süresine bakarsan önce ölçelicek alanın resmini path değişkenine atama yapıyorsun.
Kodun 6. satırında path =”1.jpg” var. Sizde ölçüm yapılacak alanı ve ölçülecek nesneyi belirleyip girişini yapmalısınız.
Hocam merhaba. *** *** ** ** numaraya yazma imkanınız var mı acaba? Birkaç sorum olacak. Gerekirse ücretli yardım veriyorsanız ona da hazırım. Yazarsanız çok sevinirim.
Sorunuzu buraya yazarsanız daha iyi olur. Kısaca anlatırsanız yapıp yapamayacağım konusunda size bilgi veririm.
Hocam dediğiniz kısımları kontrol ettim ancak halen program çalışmıyor. Ana kamera açılmasına rağmen uzunluk ölçümü yaptığı ekran açılmıyor sebebini bir türlü bulamadım.
Ben bugün veya yarın tekrar deneyeyim. Sonra buraya yazarım açıklamalı bir şekilde. Veya size mesaj atarım telefondan. Büyük ihtimalle yarın denerim.
Şimdi tekrar denedim. Kodlar gayet güzel çalışıyor. Öncelikle boş bir a4 kağıdının fotoğrafını çekip 1.jpg ismiyle kodlarla aynı klasörün içine atın. Kamerayı mümkün olduğunca uzaktan tutun. Burada benim yaptığım çalışmalar var.
https://imgyukle.com/i/EUjOGP
https://imgyukle.com/i/EUjH0e
https://imgyukle.com/i/EUjN5N
https://imgyukle.com/i/EUjjbq
https://imgyukle.com/i/EUjcrY
https://imgyukle.com/i/EUjgg0
https://imgyukle.com/i/EUjh8v
Bunlara bakarsanız çalıştığını görürsünüz.