opencv如何精準定位十字?
我想要做一個精準識別十字線中心的程序,可以實時的給出圖像中十字交點的在圖像中的坐標。
我現在的實現方案是先用形態學梯度(膨脹減去腐蝕)找出直線的大致輪廓,
然後用霍夫線檢測出直線
然後用角點檢測,可以找出四個交點,然後求平均值就能找到中點坐標。
但現在問題是檢測圖片沒有問題,但是放到視頻里,就會出現檢測不穩,
主要是形態學變換的時候後,就算鏡頭不抖,光源穩定,但腐蝕膨脹的結果圖也一直在跳動。就導致檢測出的邊緣一直在跳。
想請問知乎的大神們,有沒有更好的解決方案可以穩定的檢測到交線的正中心。多謝!!!!
/---------------------canny補充---------------------------------------/
我寫 了函數,過濾了一部分
這是最終處理結果,但是這是檢測的圖片,如果寫進視頻處理里,那就回一直抖啊抖的不停。一會少線,一會多線,根本沒法做角點檢測
/*********************************11.07**************************************/
Detech函數就是處理圖像的函數。
裡面很簡單,先換成hsv,然後通道分離,把s通道先開運算,然後分別把開運算結果賦給dilateImage和erodeImage,然後dilateImage膨脹,erodeImge腐蝕。然後相減得輪廓。
lilateImage膨脹後的圖像一直在變化,腐蝕的也是。但是原圖像沒有任何變化。
/**************************************************************************/
補充一個思路,對最後二值圖水平方向投影與垂直方向投影。在投影直方圖上找到中心附近極大值,再根據水平或垂直方向在極大值點序列中計算x、y坐標均值,基本上就是中心點。
另一個思路,如果兩條帶狀目標一直是垂直的,相機投影平面與目標物平面也是平行的條件下,直接找外輪廓上四個點,形心就是待求目標。
最後,如果在梯度圖上轉頻域處理,高頻區域應該就是交叉點附近區域。如果題主不介意使用MATLAB的話(轉成OpenCV也比較容易):
% read image
im = imread("org.jpg");
figure;imshow(im);
title("Original rgb image")
% convert to gray
imG = mat2gray(rgb2gray(im));
figure;imshow(imG)
title("Grayscale image")
% threshold using Gaussian mean (sigma=50)
imGaussianMean = imgaussfilt(imG, 50);
imBW = imG &> imGaussianMean;
figure;imshow(imBW)
title("Binary image after Gaussian filter")
% keep the largest area and morphological closing
imBW = bwareafilt(imBW,1);
imBW = bwmorph(imBW,"close");
figure;imshow(imBW)
title("Binary image after area filter and morphological closing")
% skeletonize
imSkele = bwmorph(imBW,"skel", inf);
figure;imshow(imSkele)
title("Skeleton image")
% remove spurs
imCross = bwmorph(imSkele,"spur", inf);
figure;imshow(imCross)
title("Final cross center")
% display cross and skeleton together
figure;imshowpair(im, imCross)
title("Cross center overlaid on original image")
以上代碼適用於原圖,這裡我將你的圖片旋轉了,驗證代碼也適用於旋轉後的十字。
什麼都不說,先上代碼,環境Ubuntu 16.04 opencv 3.3
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 26 11:43:10 2017
@author: zhao
"""
import numpy as np
import cv2
import matplotlib.pyplot as plt
im = cv2.imread("cross.jpg")
img_orig = np.copy(im)
im = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
im = cv2.GaussianBlur(im,(13,13),1.4,1.4)
thres,im = cv2.threshold(im,0,255,cv2.THRESH_OTSU)
plt.imshow(im,cmap="gray"),plt.show()
img,*contours = cv2.findContours(im,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
are = [cv2.contourArea(i) for i in contours[0]]
are = np.array(are)
index = np.argmax(are)
img = np.zeros(im.shape)
im = cv2.drawContours(img,contours[0],index,255,-1)
im = cv2.morphologyEx(img,cv2.MORPH_CLOSE,cv2.getStructuringElement(cv2.MORPH_RECT,(3,3)))
x_acc = np.sum(im,axis=0)
y_acc = np.sum(im,axis =1)
plt.plot(x_acc,"r")
plt.plot(y_acc,"g")
plt.show()
x_diff = np.diff(x_acc)
y_diff = np.diff(y_acc)
plt.plot(x_diff,"r")
plt.plot(y_diff,"g")
plt.show()
x_index1 = np.argmax(y_diff)
x_index2 = np.argmin(y_diff)
x_center = (x_index1+x_index2)//2
y_index1 = np.argmax(x_diff)
y_index2 = np.argmin(x_diff)
y_center = (y_index1+y_index2)//2
img_orig = cv2.circle(img_orig,(y_center,x_center),10,(0,0,255),-1)
img_orig = cv2.cvtColor(img_orig,cv2.COLOR_BGR2RGB)
plt.imshow(img_orig),plt.show()
提供個跟其他人不同的思路剛開始我也用啥邊緣檢測,但感覺效果挺差的,後來換顏色檢測,程序很簡單,但跑起來效果挺好的,不過不知道是否適應你的這個問題,所以只是提供個思路而已---------------------
用顏色檢測,沒記錯的話一般來說opencv會推薦用hsv空間,需要把常見的rgb進行到hsv的轉換,你可以利用photoshop,需要注意的是他們取值範圍是不同的,我自己今年電賽板球系統識別小球,特地找了一個騷粉騷粉的小球,白色的背景,超級容易識別,然後用的圓檢測取中心位置,感覺效果挺不錯的。我看題主的圖片感覺顏色區別度還挺大的(沒拿ps取點看值,所以具體值,差別大不大,還要你自己看啦),可以練習玩一玩,反正也沒幾行代碼,試一試唄
看到這麼多思路 正經跑過的也沒幾個 這我貼一下結果 下面有源碼 Python寫的
樓主發的圖運行結果
自己旋轉後 藍色的點是求解的中點
代碼
https://github.com/StormS0/FindCenter/blob/master/%E6%89%BE%E4%B8%AD%E7%82%B9.py
用到角點檢測和二值化 找到角點進行排序
隨便寫的 邏輯什麼的不是很好,要是有大佬的話可以幫我修正一下
第一次解答這類問題 ,好用就給個贊吧謝謝
我想到就這幾種
方案1:
二值化-取骨架-然後拿 做卷積(或者盒式濾波器),找到交點(這種方法可行性上可能還是欠考慮)。
方案2:
二值化-取骨架-然後拿構建自動機對骨架進行分析,找到交點。
方案3:
二值化-hough變換-通過兩條直線的方程求解交點
方案4:(這個答案也是前面人答過最多的答案)
二值化-位置直方圖-找到直方圖最小值(或如果是一橫一縱找最大值)處作為橫縱坐標。
方案5:(如果十字的兩條直線是從圖像的一邊到另外一邊的,即拉通圖像的)
二值化---對取骨架的演算法進行修正,對於線段端點也把它刪去,最終得到兩條沒有細小分支的細線,這個時候只有交叉點上是有分支的---再從某一條細線在邊界上的端點處開始,挨著細線一個點一個點壓棧進行搜索,找到有分支的交叉點。
方案6:
S-USAN運算元找到四個角點坐標,求中心。
為啥用角點? 求出兩條水平線的中間的線 和兩條垂線的中間的線,再求他們交點不是就行了
使用灰度圖,直接裁個十字心作子圖,在圖上做卷積,在卷積圖中找局域極值,就能定位。
你可以試試canny檢測出邊緣,然後做直線檢測,那樣就不用腐蝕和膨脹了。
一些回答沒有考慮圖像中有多餘的東西或者十字旋轉,我提供另一種思路,首先得到binary image,然後用BFS greedy search掃描整張圖一遍,得到所有的white area的blob,然後對於每個blob分別得到X方向和Y方向最大和最小的四個點,這樣我們就可以估計出這四個點生成的十字,然後跟blob中所有的其他坐標進行擬合,如果匹配就是檢測到,這樣做的好處還有就是可以很容易得到中心坐標,而且只掃整張圖每一個像素一遍,計算量應該是所有答案中最小的
怎麼定位手機號碼
簡單,dl回歸4個關鍵點
個人的方法:
直接二值化,提取十字圖像,
然後水平方向求和,取極大值。
然後豎直方向求和,取極大值。
兩個極大值就是十字中心
遇到平頂直接以平頂中間為極值。
投影求直方圖然後thresholding是比較好的做法,如果圖像略有旋轉,可以先求出四個邊上條帶中心的圖像坐標,然後求出兩條直線方程和交點,如果抖動比較厲害建議用五到十幀的moving average。
推薦閱讀:
※如何開始學慣用fpga進行圖像處理?
※請問研究生入門機器視覺C++應該自學到什麼水平?
※機器視覺新手應該如何學習?
※有哪些學習openCV的網站或書籍?
※只掌握 C 基礎可以直接學 C++ 嗎?