为了账号安全,请及时绑定邮箱和手机立即绑定

如何仅对图像的一部分执行 2D 正弦拟合?

如何仅对图像的一部分执行 2D 正弦拟合?

噜噜哒 2021-09-11 20:20:43
我有一堆图像,看起来像下面的图像,边缘厚度各不相同。我想通过 python scipy.optimize.curve_fit 函数将正弦函数拟合到这个图像。然而,如图所示,条纹图案仅限制在圆形区域内。那我该如何进行拟合呢?
查看完整描述

1 回答

?
杨__羊羊

TA贡献1943条经验 获得超7个赞

我想如果我是你,我会想要一个函数来近似与它们成 90 度的条纹……这样我就可以抓住正弦函数的周期。这将是一个多步骤的解决方案。


1) 抓住边缘最亮的区域


2) 沿与条纹垂直的线获取图像的值


3) 计算最佳拟合曲线。


import cv2

import numpy as np

from matplotlib import pyplot as plt

import math


#function to rotate an image around a point

def rotateImage(image, angle):

    image_center = tuple(np.array(image.shape[1::-1]) / 2)

    rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)

    result = cv2.warpAffine(image, rot_mat, image.shape[1::-1], flags=cv2.INTER_LINEAR)

    return result



img = cv2.imread('sin.png', cv2.IMREAD_GRAYSCALE)



imgb = cv2.GaussianBlur(img, (7,7),0)

plt.imshow(imgb)

plt.show()


#grap bright values

v90 = np.percentile(imgb, 90)

#get mask for bright values

msk = imgb >= v90

msk = msk.astype(np.uint8)


plt.imshow(msk)

plt.show()


#get contours

cnts = cv2.findContours(msk, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]


cnt = sorted(cnts, key=cv2.contourArea)

c = np.vstack((cnt[-2], cnt[-1])) #combine 2 largest


((cx, cy), radius) = cv2.minEnclosingCircle(c)

cv2.circle(img, (int(cx), int(cy)), int(radius), 255, 2)

plt.imshow(img)

plt.show()


#circle is just for show...use if you want.

//img1.sycdn.imooc.com//613c9f530001d67903860821.jpg

imc = img.copy()

#take top 5 contours(4 would work too ymmv)

angles = []

for i in range(5):

    c = cnt[-(i+1)]

    ellipse = cv2.fitEllipse(c)

    (x, y), (MA, ma), angle = cv2.fitEllipse(c)

    cv2.ellipse(imc, ((x, y), (MA, ma), angle), 255, 2)

    angles.append(angle)


#average angle  of ellipse.

mangle = np.mean(angles)


#goal is create a line normal to the average angle of the ellipses.

#the 0.6 factor here is to just grab the inner region...which will avoid the rapid fall-off of the envelop gaussian-like function.

pt1 = (int(cx + .6*radius*math.cos(math.radians(mangle))), int(cy + .6*radius*math.sin(math.radians(mangle))))

pt2 = (int(cx - .6*radius*math.cos(math.radians(mangle))), int(cy - .6*radius*math.sin(math.radians(mangle))))


#show line

cv2.line(imc, pt1, pt2, 255, 2)


#put fat line on mask...will use this to sample from original image later

im4mask = np.zeros(imc.shape).astype(np.uint8)

cv2.line(im4mask, pt1, pt2, 255, 9)


plt.imshow(imc)

plt.show()


plt.imshow(im4mask)

plt.show()

//img1.sycdn.imooc.com//613c9f610001b79f03820521.jpg

#now do some rotating(to make the numpy slicing later easier)


imnew = rotateImage(imc, mangle)

plt.imshow(imnew)

plt.show()


im4maskrot = rotateImage(im4mask, mangle)

im4maskrot[im4maskrot > 20] = 255

plt.imshow(im4maskrot)

plt.show()


imgbrot = rotateImage(imgb, mangle)

plt.imshow(imgbrot)

plt.show()


#gather values from original

ys, xs = np.where(im4maskrot == 255)

minx = np.min(xs)

miny = np.min(ys)

maxx = np.max(xs)

maxy = np.max(ys)

print 'x ', minx, maxx

print 'y ', miny, maxy

crop = imgbrot[miny:maxy, minx:maxx]

print crop.shape

plt.imshow(crop)

plt.show()


plt.plot(range(crop.shape[1]), np.mean(crop, axis=0))

//img1.sycdn.imooc.com//613c9f700001925903750787.jpg

//img1.sycdn.imooc.com//613c9f760001c34b03990346.jpg

#now time to fit a curve.

#first with a gaussian


from scipy import optimize


def test_func(x, a, b, A, mu, sigma):

    return A*np.exp(-(x-mu)**2/(2.*sigma**2)) + a * np.sin(b * x)


params, params_covariance = optimize.curve_fit(test_func, np.arange(crop.shape[1]), np.mean(crop, axis=0), p0=[10, 1/15., 60, 2, 150], maxfev=200000000)


print(params)


plt.figure(figsize=(6, 4))

plt.scatter(range(crop.shape[1]), np.mean(crop, axis=0), label='Data')

plt.plot(np.arange(crop.shape[1]), test_func(np.arange(crop.shape[1]), params[0],     params[1], params[2], params[3], params[4]), label='Fitted function')


plt.legend(loc='best')

plt.show()


//img1.sycdn.imooc.com//613c9f9000014e0304880308.jpg

#and without a gaussian...the result is close because of only grabbing a short region.


def test_func(x, a, b, n):

    return n + a * np.sin(b * x)


params, params_covariance = optimize.curve_fit(test_func, np.arange(crop.shape[1]), np.mean(crop, axis=0), p0=[10, 1/15., 60], maxfev=200000000)


print(params)


plt.figure(figsize=(6, 4))

plt.scatter(range(crop.shape[1]), np.mean(crop, axis=0), label='Data')

plt.plot(np.arange(crop.shape[1]), test_func(np.arange(crop.shape[1]), params[0], params[1], params[2]), label='Fitted function')


plt.legend(loc='best')


plt.show()

//img1.sycdn.imooc.com//613c9f980001ee2703920278.jpg

请注意,b参数与周期性有关,并且两个值彼此非常接近(0.0644 和 0.0637)。知道了这一点,我会选择更简单的曲线拟合,因为起始参数更少。


查看完整回答
反对 回复 2021-09-11
  • 1 回答
  • 0 关注
  • 189 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信