首先感謝《利用Python求解帶約束的最優化問題》讓我不用自己重0開始敲代碼了!不過就是效率有點慢了,還在解決中,至少問題有解了~
=================== 問題描述 =======================
昨天項目例會上產品提了一個看似很正常但是細想卻很棘手的要求,在前端頁面上展示出來的內容如果僅僅只有分割網絡的結果會很奇怪,對用戶的體驗不好,他需要在包含目標的bbox基礎上向外擴充一點,即符合前端展示的長寬比例又要突出重點(檢測網絡出的結果)。初看沒毛病,也沒啥困難的地方。可是當去準備給出這個座標的時候就傻了!擴多少?檢測出來的bbox長寬比千奇百怪,怎麼變成符合前端需要的長寬比?還不能一個不動,只動另一個,這樣做的結果很奇怪,我昨天就這麼幹過一次/捂臉。圖中綠色的框就是我的bbox,藍色的框就是我的目標(前端只顯示藍色框中的內容!),要向外擴的(爲了避免不適,我把重點都馬賽克了)
========================== 數學好好玩========================
問題轉換成,已知bbox、目標矩形的長寬比hw_rate,求一個extented_bbox,符合extented_bbox.h/extented_bbox.w = hw_rate,且extented_bbox.area不能太小或太大,暫且定義成bbox.area/extented_bbox.area <=0.8,設寬和長各需擴充x,y,原bbox的長寬爲h,w,目標長寬比爲r,則有:
st.
最小化z即可,然後將求得的x,y帶入就是一個符合r的最小框,這時得到的(w+x)和(h+y)還不是最終結果,只是求得了一個符合目標長寬比的值,然後再一點點的向外擴,由於沒人知道到底擴多少合適,大概滿足前端可以再綠色和藍色的中間地帶寫字即可,我留了100像素。不過這裏有個問題,一直不明白爲什麼,就是不等式約束條件寫成上面的形式就有結果,如果寫成(wh)/(w+x)(h+y)<=0.8這種就無解了。知道的還請說一聲,謝謝先~
代碼幾乎和《利用Python求解帶約束的最優化問題》一樣,只是把公式改成了我自己的公式
from sympy import *
def bbox_extened(w, h, wh_rate, area_rate):
# 設置變量
deltaW = symbols("deltaW")
deltaH = symbols("deltaH")
alpha = symbols("alpha")
beta = symbols("beta")
# 構造拉格朗日等式
L = (w + deltaW) * (h + deltaH) + \
alpha * (((w + deltaW) * (h + deltaH)) / (w * h) - area_rate) + \
beta * ((w + deltaW) / (h + deltaH) - wh_rate)
# 求導,構造KKT條件
difyL_x1 = diff(L, deltaW) # 對變量x1求導
difyL_x2 = diff(L, deltaH) # 對變量x2求導
difyL_beta = diff(L, beta) # 對乘子beta求導
dualCpt = alpha * (((w + deltaW) * (h + deltaH)) / (w * h) - area_rate) # 對偶互補條件
# 求解KKT等式
res = solve([difyL_x1, difyL_x2, difyL_beta, dualCpt], [deltaW, deltaH, alpha, beta])
# for item in res:
# print(item)
# print((w*h)/((w + item[0]) * (h + item[1])))
return res