我嘗試測量單個礫石顆粒的寬度。我需要這個來識別它是細礫石還是粗礫石。你能幫我,我怎樣才能找到礫石輪廓的兩個極端部分?到目前為止,我只是試圖從圖片中獲取輪廓。(代碼下的照片)我當前的代碼:
import cv2
import numpy as np
def empty(a):
pass
path = "materials/gr2.jpeg"
path2 = "materials/gr1.jpeg"
cv2.namedWindow("TrackBars")
#cv2.resizeWindow("TrackBars",740,280)
cv2.createTrackbar("Hue Min", "TrackBars",0,179,empty)
cv2.createTrackbar("Hue Max", "TrackBars",179,179,empty)
cv2.createTrackbar("Sat Min", "TrackBars",0,255,empty)
cv2.createTrackbar("Sat Max", "TrackBars",255,255,empty)
cv2.createTrackbar("Val Min", "TrackBars",147,255,empty)
cv2.createTrackbar("Val Max", "TrackBars",255,255,empty)
img = cv2.imread(path)
img2 = cv2.imread(path2)
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
imgHSV2 = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV)
while True:
h_min = cv2.getTrackbarPos("Hue Min", "TrackBars")
h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
print(h_min,h_max,s_min,s_max,v_min,v_max)
lower = np.array([h_min,s_min,v_min])
upper = np.array([h_max,s_max,v_max])
mask = cv2.inRange(imgHSV,lower,upper)
mask2 = cv2.inRange(imgHSV2,lower,upper)
cv2.imshow("Mask2", mask2)
cv2.imshow("Mask", mask)
cv2.waitKey(1)

uj5u.com熱心網友回復:
以下是一些使用拉普拉斯金字塔的統計資料。
忽略前幾個級別,這是由于光照不均勻和濕礫石與干礫石造成的。
您可以看到在較低/較細的級別(接近 10)中,細礫石的回應更多,而粗礫石的回應向上。
coarse vs fine
[ 0] 351399 : 385660 # ignore that, that's the DC component
[ 1] 75 : 95
[ 2] 177 : 184
[ 3] 130 : 78
[ 4] 408 : 94
[ 5] 1352 : 215
[ 6] 4051 : 706
[ 7] 7784 : 2123
[ 8] 8521 : 4814
[ 9] 6838 : 8108
[10] 8207 : 12775
#!/usr/bin/env python3
import os
import sys
from math import *
import numpy as np
import cv2 as cv
np.set_printoptions(suppress=True, linewidth=120)
im1 = cv.imread("coarse dCrrR.jpg", cv.IMREAD_GRAYSCALE)
im2 = cv.imread("fine xvmKD.jpg", cv.IMREAD_GRAYSCALE)
levels = 10
sw = sh = 2**levels
def take_sample(im):
h,w = im.shape[:2]
return im[(h-sh) // 2 : (h sh) // 2, (w-sw) // 2 : (w sw) // 2]
def gaussian_pyramid(sample):
gp = [sample]
for k in range(levels):
sample = cv.pyrDown(sample)
gp.append(sample)
return gp
def laplacian_pyramid(gp):
lp = [gp[-1]] # "base" gaussian
for k in reversed(range(levels)):
diff = gp[k] - cv.pyrUp(gp[k 1])
lp.append(diff)
return lp
sample1 = take_sample(im1) * np.float32(1/255)
sample2 = take_sample(im2) * np.float32(1/255)
gp1 = gaussian_pyramid(sample1)
gp2 = gaussian_pyramid(sample2)
lp1 = laplacian_pyramid(gp1)
lp2 = laplacian_pyramid(gp2)
print("coarse vs fine")
for i,(level1,level2) in enumerate(zip(lp1, lp2)):
area = 2**(2*i)
sse1 = (level1**2).sum() / area
sse2 = (level2**2).sum() / area
print(f"[{i:2d}] {sse1*1e6:8.0f} : {sse2*1e6:8.0f}")
uj5u.com熱心網友回復:
如果對影像中平均礫石大小的粗略估計就足夠了,您可以嘗試這種演算法,它確實非常粗略,而且可能不準確(您必須對更多影像進行測驗,是否在統計上有意義)
1. threshold for bright gravel stones
2. subtract the edges between stones
3. extract external contours and discard too small ones (magic number)
4. choose any comparison point in the sorted contour area list (e.g. median = 50%)
給出這些結果:
精細影像 => 中值輪廓區域:31
粗糙影像 => 中值輪廓區域 89.5
使用這些用于計算輪廓的掩碼影像:


從這個源代碼:
int main()
{
try
{
cv::Mat img = cv::imread("C:/data/StackOverflow/gravel/coarse.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat thresh;
double t = cv::threshold(img, thresh, 255, 255, cv::THRESH_OTSU | cv::THRESH_BINARY);
//thresh = img > t * 1.5; // doesnt work as well as removing the edges
cv::Mat sobelX, sobelY;
cv::Sobel(img, sobelX, CV_32FC1, 1, 0, 3, 1.0, 0);
cv::Sobel(img, sobelY, CV_32FC1, 0, 1, 3, 1.0, 0);
cv::Mat sobelMag_FC;
cv::Mat sobelMag_8U;
cv::Mat sobelBin;
cv::magnitude(sobelX, sobelY, sobelMag_FC);
sobelMag_FC.convertTo(sobelMag_8U, CV_8U);
double t2 = cv::threshold(sobelMag_8U, sobelBin, 255, 255, cv::THRESH_OTSU | cv::THRESH_BINARY);
//sobelBin = sobelMag_FC > 150; // doesnt work as well
cv::Mat gravel = thresh - sobelBin;
std::vector<std::vector<cv::Point> > contours;
cv::findContours(gravel, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
std::vector<double> contourAreas;
for (int i = 0; i < contours.size(); i)
{
double area = cv::contourArea(contours[i]);
if(area > 10) contourAreas.push_back(area); // magic number for minimum contour area...
}
std::sort(contourAreas.begin(), contourAreas.end());
// choose a single comparison point (e.g. 50% position in the list => median)
std::cout << contourAreas.at(contourAreas.size() *0.5) << std::endl;
cv::imwrite("C:/data/StackOverflow/gravel/coarse_mask.png", gravel);
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
std::cin.get();
}
}
你可以看到有很多微小的輪廓和連接的礫石等。所以可能整個演算法最終都是垃圾,但給出了一些或多或少合理的兩個影像的相對大小結果。
添加 1000 的 max-contour-size 并測驗更多比較點:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/382331.html
