[英]Automatic contrast and brightness adjustment of a color photo of a sheet of paper with OpenCV
拍攝一張紙時(例如使用手機相機),我得到以下結果(左圖)(jpg在這里下載)。 所需的結果(使用圖像編輯軟件手動處理)在右側:
我想用 openCV 處理原始圖像以自動獲得更好的亮度/對比度(使背景更白) 。
假設:圖像具有 A4 縱向格式(我們不需要在本主題中對其進行透視變形),並且這張紙是白色的,可能帶有黑色或彩色的文本/圖像。
到目前為止我嘗試過的:
各種自適應閾值方法,例如 Gaussian、OTSU(請參閱 OpenCV 文檔圖像閾值)。 它通常適用於 OTSU:
ret, gray = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)
但它僅適用於灰度圖像,不能直接用於彩色圖像。 此外,輸出是二進制(白色或黑色),我不想要:我更喜歡保留彩色非二進制圖像作為輸出
如本建議答案( 直方圖均衡化不是彩色圖像的工作- OpenCV的)或該一個( OpenCV的Python的equalizeHist彩色圖像):
img3 = cv2.imread(f) img_transf = cv2.cvtColor(img3, cv2.COLOR_BGR2YUV) img_transf[:,:,0] = cv2.equalizeHist(img_transf[:,:,0]) img4 = cv2.cvtColor(img_transf, cv2.COLOR_YUV2BGR) cv2.imwrite('test.jpg', img4)
或與HSV:
img_transf = cv2.cvtColor(img3, cv2.COLOR_BGR2HSV) img_transf[:,:,2] = cv2.equalizeHist(img_transf[:,:,2]) img4 = cv2.cvtColor(img_transf, cv2.COLOR_HSV2BGR)
不幸的是,結果非常糟糕,因為它在本地產生了可怕的微觀對比(?):
我也嘗試過 YCbCr,它是相似的。
我還嘗試了CLAHE(對比度限制自適應直方圖均衡化),使用從1
到1000
各種tileGridSize
:
img3 = cv2.imread(f) img_transf = cv2.cvtColor(img3, cv2.COLOR_BGR2HSV) clahe = cv2.createCLAHE(tileGridSize=(100,100)) img_transf[:,:,2] = clahe.apply(img_transf[:,:,2]) img4 = cv2.cvtColor(img_transf, cv2.COLOR_HSV2BGR) cv2.imwrite('test.jpg', img4)
但結果也同樣糟糕。
使用 LAB 顏色空間執行此 CLAHE 方法,如問題How to apply CLAHE on RGB color images 中所述:
import cv2, numpy as np bgr = cv2.imread('_example.jpg') lab = cv2.cvtColor(bgr, cv2.COLOR_BGR2LAB) lab_planes = cv2.split(lab) clahe = cv2.createCLAHE(clipLimit=2.0,tileGridSize=(100,100)) lab_planes[0] = clahe.apply(lab_planes[0]) lab = cv2.merge(lab_planes) bgr = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) cv2.imwrite('_example111.jpg', bgr)
結果也不好。 輸出圖像:
每個通道(R,G,B)上分別做一個自適應閾值或直方圖均衡是不因為它會弄亂顏色平衡,如所解釋的選項這里。
來自scikit-image
的直方圖均衡化教程的“對比度拉伸”方法:
圖像被重新縮放以包括落在第 2 個和第 98 個百分位數內的所有強度
好一點,但仍遠未達到預期的結果(請參閱此問題頂部的圖片)。
TL;DR:如何使用 OpenCV/Python 對一張紙的彩色照片進行自動亮度/對比度優化? 可以使用什么樣的閾值/直方圖均衡/其他技術?
亮度和對比度可以分別使用 alpha (α) 和 beta (β) 進行調整。 表達式可以寫成
OpenCV 已經將其作為cv2.convertScaleAbs()
因此我們可以僅將此函數與用戶定義的alpha
和beta
值一起使用。
import cv2
import numpy as np
from matplotlib import pyplot as plt
image = cv2.imread('1.jpg')
alpha = 1.95 # Contrast control (1.0-3.0)
beta = 0 # Brightness control (0-100)
manual_result = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)
cv2.imshow('original', image)
cv2.imshow('manual_result', manual_result)
cv2.waitKey()
但問題是
如何獲得彩色照片的自動亮度/對比度優化?
本質上的問題是如何自動計算alpha
和beta
。 為此,我們可以查看圖像的直方圖。 自動亮度和對比度優化計算 alpha 和 beta,以便輸出范圍為[0...255]
。 我們計算累積分布以確定顏色頻率小於某個閾值(例如 1%)的位置,並切割直方圖的右側和左側。 這為我們提供了最小和最大范圍。 這是裁剪前(藍色)和裁剪后(橙色)的直方圖的可視化。 請注意圖像中更“有趣”的部分在剪裁后如何更加明顯。
為了計算alpha
,我們取裁剪后的最小和最大灰度范圍,並將它與我們期望的輸出范圍255
α = 255 / (maximum_gray - minimum_gray)
為了計算 beta,我們將其代入公式中,其中g(i, j)=0
和f(i, j)=minimum_gray
g(i,j) = α * f(i,j) + β
在解決這個結果之后
β = -minimum_gray * α
對於您的形象,我們得到了這個
阿爾法:3.75
測試版:-311.25
您可能需要調整裁剪閾值以優化結果。 以下是使用 1% 閾值與其他圖像的一些示例結果
自動亮度和對比度代碼
import cv2
import numpy as np
from matplotlib import pyplot as plt
# Automatic brightness and contrast optimization with optional histogram clipping
def automatic_brightness_and_contrast(image, clip_hist_percent=1):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Calculate grayscale histogram
hist = cv2.calcHist([gray],[0],None,[256],[0,256])
hist_size = len(hist)
# Calculate cumulative distribution from the histogram
accumulator = []
accumulator.append(float(hist[0]))
for index in range(1, hist_size):
accumulator.append(accumulator[index -1] + float(hist[index]))
# Locate points to clip
maximum = accumulator[-1]
clip_hist_percent *= (maximum/100.0)
clip_hist_percent /= 2.0
# Locate left cut
minimum_gray = 0
while accumulator[minimum_gray] < clip_hist_percent:
minimum_gray += 1
# Locate right cut
maximum_gray = hist_size -1
while accumulator[maximum_gray] >= (maximum - clip_hist_percent):
maximum_gray -= 1
# Calculate alpha and beta values
alpha = 255 / (maximum_gray - minimum_gray)
beta = -minimum_gray * alpha
'''
# Calculate new histogram with desired range and show histogram
new_hist = cv2.calcHist([gray],[0],None,[256],[minimum_gray,maximum_gray])
plt.plot(hist)
plt.plot(new_hist)
plt.xlim([0,256])
plt.show()
'''
auto_result = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)
return (auto_result, alpha, beta)
image = cv2.imread('1.jpg')
auto_result, alpha, beta = automatic_brightness_and_contrast(image)
print('alpha', alpha)
print('beta', beta)
cv2.imshow('auto_result', auto_result)
cv2.waitKey()
帶有此代碼的結果圖像:
使用 1% 閾值的其他圖像的結果
另一種版本是使用飽和度算法而不是使用 OpenCV 的cv2.convertScaleAbs
為圖像添加偏差和增益。 內置方法不采用絕對值,這會導致無意義的結果(例如,在 alpha = 3 和 beta = -210 的情況下,44 處的像素在 OpenCV 中變為 78,而實際上它應該變為 0)。
import cv2
import numpy as np
# from matplotlib import pyplot as plt
def convertScale(img, alpha, beta):
"""Add bias and gain to an image with saturation arithmetics. Unlike
cv2.convertScaleAbs, it does not take an absolute value, which would lead to
nonsensical results (e.g., a pixel at 44 with alpha = 3 and beta = -210
becomes 78 with OpenCV, when in fact it should become 0).
"""
new_img = img * alpha + beta
new_img[new_img < 0] = 0
new_img[new_img > 255] = 255
return new_img.astype(np.uint8)
# Automatic brightness and contrast optimization with optional histogram clipping
def automatic_brightness_and_contrast(image, clip_hist_percent=25):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Calculate grayscale histogram
hist = cv2.calcHist([gray],[0],None,[256],[0,256])
hist_size = len(hist)
# Calculate cumulative distribution from the histogram
accumulator = []
accumulator.append(float(hist[0]))
for index in range(1, hist_size):
accumulator.append(accumulator[index -1] + float(hist[index]))
# Locate points to clip
maximum = accumulator[-1]
clip_hist_percent *= (maximum/100.0)
clip_hist_percent /= 2.0
# Locate left cut
minimum_gray = 0
while accumulator[minimum_gray] < clip_hist_percent:
minimum_gray += 1
# Locate right cut
maximum_gray = hist_size -1
while accumulator[maximum_gray] >= (maximum - clip_hist_percent):
maximum_gray -= 1
# Calculate alpha and beta values
alpha = 255 / (maximum_gray - minimum_gray)
beta = -minimum_gray * alpha
'''
# Calculate new histogram with desired range and show histogram
new_hist = cv2.calcHist([gray],[0],None,[256],[minimum_gray,maximum_gray])
plt.plot(hist)
plt.plot(new_hist)
plt.xlim([0,256])
plt.show()
'''
auto_result = convertScale(image, alpha=alpha, beta=beta)
return (auto_result, alpha, beta)
image = cv2.imread('1.jpg')
auto_result, alpha, beta = automatic_brightness_and_contrast(image)
print('alpha', alpha)
print('beta', beta)
cv2.imshow('auto_result', auto_result)
cv2.imwrite('auto_result.png', auto_result)
cv2.imshow('image', image)
cv2.waitKey()
我以前做過類似的事情,目的有點不同,所以這可能不完全適合您的需求,但希望它有所幫助(我也是在晚上寫了這段代碼供個人使用,所以它很丑陋)。 從某種意義上說,與您的情況相比,此代碼旨在解決更一般的情況,在這種情況下,我們可以在背景中產生大量結構化噪聲(請參見下面的演示)。
這段代碼有什么作用? 給定一張紙的照片,它會將它變白,以便它可以完美地打印。 請參閱下面的示例圖像。
預告:這就是你的頁面在這個算法之后的樣子(之前和之后)。 請注意,即使顏色標記注釋也不見了,所以我不知道這是否適合您的用例,但代碼可能有用:
為了獲得完美干凈的結果,您可能需要稍微調整過濾參數,但正如您所見,即使使用默認參數,它也能很好地工作。
假設您以某種方式執行了此步驟(在您提供的示例中似乎是這樣)。 如果您需要手動注釋和重新扭曲工具,請私信我! ^^ 這一步的結果如下(我在這里使用的例子可以說比你提供的例子更難,雖然它可能不完全符合你的情況):
由此我們可以立即看出以下問題:
OpenCV
可用的解決方案,以及它們的組合,都沒有奏效!這一步的原因是為了平衡整個圖像的對比度(因為根據光照條件,您的圖像可能會稍微曝光過度/曝光不足)。
這乍一看似乎是一個不必要的步驟,但它的重要性不容低估:從某種意義上說,它將圖像歸一化為相似的曝光分布,以便您以后可以選擇有意義的超參數(例如DELTA
參數下一節,噪聲過濾參數,形態學參數等)
# Somehow I found the value of `gamma=1.2` to be the best in my case
def adjust_gamma(image, gamma=1.2):
# build a lookup table mapping the pixel values [0, 255] to
# their adjusted gamma values
invGamma = 1.0 / gamma
table = np.array([((i / 255.0) ** invGamma) * 255
for i in np.arange(0, 256)]).astype("uint8")
# apply gamma correction using the lookup table
return cv2.LUT(image, table)
以下是伽馬調整的結果:
你可以看到它現在有點……“平衡”了。 如果沒有這一步,您將在后面的步驟中手動選擇的所有參數都將變得不那么健壯!
在這一步中,我們將自適應地二值化文本 blob。 我稍后會添加更多評論,但這個想法基本上如下:
BLOCK_SIZE
塊。 訣竅是選擇足夠大的尺寸,這樣您仍然可以獲得一大塊文本和背景(即比您擁有的任何符號都大),但又要小到不會受到任何光照條件變化的影響(即“大,但仍然當地的”)。BLOCK_SIZE
足夠大以使其大部分成為背景)。 然后,我們進一步定義DELTA
基本上只是一個閾值,即“我們仍將其視為背景離中位數有多遠?”。 因此,函數process_image
完成了工作。 此外,您可以修改preprocess
和postprocess
函數以滿足您的需要(但是,正如您從上面的示例中看到的,該算法非常健壯,即它開箱即用,無需修改太多參數)。
這部分的代碼假設前景比背景更暗(即紙上的墨水)。 但是你可以通過調整preprocess
函數輕松改變它:而不是255 - image
,只返回image
。
# These are probably the only important parameters in the
# whole pipeline (steps 0 through 3).
BLOCK_SIZE = 40
DELTA = 25
# Do the necessary noise cleaning and other stuffs.
# I just do a simple blurring here but you can optionally
# add more stuffs.
def preprocess(image):
image = cv2.medianBlur(image, 3)
return 255 - image
# Again, this step is fully optional and you can even keep
# the body empty. I just did some opening. The algorithm is
# pretty robust, so this stuff won't affect much.
def postprocess(image):
kernel = np.ones((3,3), np.uint8)
image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
return image
# Just a helper function that generates box coordinates
def get_block_index(image_shape, yx, block_size):
y = np.arange(max(0, yx[0]-block_size), min(image_shape[0], yx[0]+block_size))
x = np.arange(max(0, yx[1]-block_size), min(image_shape[1], yx[1]+block_size))
return np.meshgrid(y, x)
# Here is where the trick begins. We perform binarization from the
# median value locally (the img_in is actually a slice of the image).
# Here, following assumptions are held:
# 1. The majority of pixels in the slice is background
# 2. The median value of the intensity histogram probably
# belongs to the background. We allow a soft margin DELTA
# to account for any irregularities.
# 3. We need to keep everything other than the background.
#
# We also do simple morphological operations here. It was just
# something that I empirically found to be "useful", but I assume
# this is pretty robust across different datasets.
def adaptive_median_threshold(img_in):
med = np.median(img_in)
img_out = np.zeros_like(img_in)
img_out[img_in - med < DELTA] = 255
kernel = np.ones((3,3),np.uint8)
img_out = 255 - cv2.dilate(255 - img_out,kernel,iterations = 2)
return img_out
# This function just divides the image into local regions (blocks),
# and perform the `adaptive_mean_threshold(...)` function to each
# of the regions.
def block_image_process(image, block_size):
out_image = np.zeros_like(image)
for row in range(0, image.shape[0], block_size):
for col in range(0, image.shape[1], block_size):
idx = (row, col)
block_idx = get_block_index(image.shape, idx, block_size)
out_image[block_idx] = adaptive_median_threshold(image[block_idx])
return out_image
# This function invokes the whole pipeline of Step 2.
def process_image(img):
image_in = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
image_in = preprocess(image_in)
image_out = block_image_process(image_in, BLOCK_SIZE)
image_out = postprocess(image_out)
return image_out
結果是像這樣的漂亮斑點,緊跟墨跡:
有了覆蓋符號的斑點以及更多的斑點,我們終於可以進行白化程序了。
如果我們仔細觀察帶有文字的紙張(尤其是那些有手寫的紙張)的照片,從“背景”(白紙)到“前景”(深色墨水)的轉變並不明顯,而是非常漸進的. 本節中其他基於二值化的答案提出了一個簡單的閾值(即使它們是本地自適應的,它仍然是一個閾值),它適用於印刷文本,但會產生不那么漂亮的手寫結果。
因此,本節的動機是我們希望保留從黑色到白色逐漸傳輸的效果,就像使用自然墨水的紙張的自然照片一樣。 這樣做的最終目的是使其可打印。
主要思想很簡單:像素值(經過上面的閾值處理后)與局部最小值的差異越大,它就越有可能屬於背景。 我們可以使用一系列Sigmoid函數來表達這一點,重新縮放到局部塊的范圍(以便該函數在整個圖像中自適應地縮放)。
# This is the function used for composing
def sigmoid(x, orig, rad):
k = np.exp((x - orig) * 5 / rad)
return k / (k + 1.)
# Here, we combine the local blocks. A bit lengthy, so please
# follow the local comments.
def combine_block(img_in, mask):
# First, we pre-fill the masked region of img_out to white
# (i.e. background). The mask is retrieved from previous section.
img_out = np.zeros_like(img_in)
img_out[mask == 255] = 255
fimg_in = img_in.astype(np.float32)
# Then, we store the foreground (letters written with ink)
# in the `idx` array. If there are none (i.e. just background),
# we move on to the next block.
idx = np.where(mask == 0)
if idx[0].shape[0] == 0:
img_out[idx] = img_in[idx]
return img_out
# We find the intensity range of our pixels in this local part
# and clip the image block to that range, locally.
lo = fimg_in[idx].min()
hi = fimg_in[idx].max()
v = fimg_in[idx] - lo
r = hi - lo
# Now we use good old OTSU binarization to get a rough estimation
# of foreground and background regions.
img_in_idx = img_in[idx]
ret3,th3 = cv2.threshold(img_in[idx],0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Then we normalize the stuffs and apply sigmoid to gradually
# combine the stuffs.
bound_value = np.min(img_in_idx[th3[:, 0] == 255])
bound_value = (bound_value - lo) / (r + 1e-5)
f = (v / (r + 1e-5))
f = sigmoid(f, bound_value + 0.05, 0.2)
# Finally, we re-normalize the result to the range [0..255]
img_out[idx] = (255. * f).astype(np.uint8)
return img_out
# We do the combination routine on local blocks, so that the scaling
# parameters of Sigmoid function can be adjusted to local setting
def combine_block_image_process(image, mask, block_size):
out_image = np.zeros_like(image)
for row in range(0, image.shape[0], block_size):
for col in range(0, image.shape[1], block_size):
idx = (row, col)
block_idx = get_block_index(image.shape, idx, block_size)
out_image[block_idx] = combine_block(
image[block_idx], mask[block_idx])
return out_image
# Postprocessing (should be robust even without it, but I recommend
# you to play around a bit and find what works best for your data.
# I just left it blank.
def combine_postprocess(image):
return image
# The main function of this section. Executes the whole pipeline.
def combine_process(img, mask):
image_in = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
image_out = combine_block_image_process(image_in, mask, 20)
image_out = combine_postprocess(image_out)
return image_out
有些東西被評論,因為它們是可選的。 combine_process
函數從上一步中獲取掩碼,並執行整個組合管道。 您可以嘗試使用它們來獲取特定數據(圖像)。 結果很整潔:
可能我會在此答案中為代碼添加更多注釋和解釋。 將在 Github 上上傳整個內容(連同裁剪和變形代碼)。
這種方法應該適用於您的應用程序。 首先,您會找到一個閾值,它可以在強度直方圖中很好地分離分布模式,然后使用該值重新調整強度。
from skimage.filters import threshold_yen
from skimage.exposure import rescale_intensity
from skimage.io import imread, imsave
img = imread('mY7ep.jpg')
yen_threshold = threshold_yen(img)
bright = rescale_intensity(img, (0, yen_threshold), (0, 255))
imsave('out.jpg', bright)
我在這里使用 Yen 的方法,可以在此頁面上了解有關此方法的更多信息。
我認為這樣做的方法是 1) 從 HCL 色彩空間中提取色度(飽和度)通道。 (HCL 比 HSL 或 HSV 效果更好)。 只有顏色應該具有非零飽和度,所以明亮,灰色陰影會變暗。 2) 閾值使用 otsu 閾值作為掩碼使用的結果。 3) 將您的輸入轉換為灰度並應用局部區域(即自適應)閾值。 4) 將mask放入原圖的alpha通道,然后將局部區域閾值結果與原圖合成,使得彩色區域與原圖保持一致,其他地方都使用局部區域閾值結果。
抱歉,我不太了解 OpeCV,但這里是使用 ImageMagick 的步驟。
請注意,通道從 0 開始編號。(H=0 或紅色,C=1 或綠色,L=2 或藍色)
輸入:
magick image.jpg -colorspace HCL -channel 1 -separate +channel tmp1.png
magick tmp1.png -auto-threshold otsu tmp2.png
magick image.jpg -colorspace gray -negate -lat 20x20+10% -negate tmp3.png
magick tmp3.png \( image.jpg tmp2.png -alpha off -compose copy_opacity -composite \) -compose over -composite result.png
添加:
這是 Python Wand 代碼,它產生相同的輸出結果。 它需要 Imagemagick 7 和 Wand 0.5.5。
#!/bin/python3.7
from wand.image import Image
from wand.display import display
from wand.version import QUANTUM_RANGE
with Image(filename='text.jpg') as img:
with img.clone() as copied:
with img.clone() as hcl:
hcl.transform_colorspace('hcl')
with hcl.channel_images['green'] as mask:
mask.auto_threshold(method='otsu')
copied.composite(mask, left=0, top=0, operator='copy_alpha')
img.transform_colorspace('gray')
img.negate()
img.adaptive_threshold(width=20, height=20, offset=0.1*QUANTUM_RANGE)
img.negate()
img.composite(copied, left=0, top=0, operator='over')
img.save(filename='text_process.jpg')
首先,我們將文本和顏色標記分開。 這可以在具有色彩飽和度通道的色彩空間中完成。 我改用了一種受 本文啟發的非常簡單的方法:對於(淺色)灰色區域,min(R,G,B)/max(R,G,B) 的比率將接近 1,對於彩色區域,<<1。 對於深灰色區域,我們得到 0 到 1 之間的任何值,但這並不重要:這些區域要么進入顏色蒙版,然后按原樣添加,要么不包含在蒙版中,並有助於二值化的輸出文本。 對於黑色,我們使用轉換為 uint8 時 0/0 變為 0 的事實。
灰度圖像文本被局部閾值化以產生黑白圖像。 你可以從這個比較或那個調查中選擇你最喜歡的技術。 我選擇了 NICK 技術,它可以很好地處理低對比度並且相當穩健,即在大約 -0.3 和 -0.1 之間選擇參數k
適用於非常廣泛的條件,這有利於自動處理。 對於提供的示例文檔,所選擇的技術並沒有起到很大的作用,因為它是相對均勻的照明,但為了處理非均勻照明的圖像,它應該是一種局部閾值技術。
在最后一步,顏色區域被添加回二值化的文本圖像。
所以這個解決方案與@fmw42 的解決方案非常相似(所有的想法都歸功於他),除了不同的顏色檢測和二值化方法。
image = cv2.imread('mY7ep.jpg')
# make mask and inverted mask for colored areas
b,g,r = cv2.split(cv2.blur(image,(5,5)))
np.seterr(divide='ignore', invalid='ignore') # 0/0 --> 0
m = (np.fmin(np.fmin(b, g), r) / np.fmax(np.fmax(b, g), r)) * 255
_,mask_inv = cv2.threshold(np.uint8(m), 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
mask = cv2.bitwise_not(mask_inv)
# local thresholding of grayscale image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
text = cv2.ximgproc.niBlackThreshold(gray, 255, cv2.THRESH_BINARY, 41, -0.1, binarizationMethod=cv2.ximgproc.BINARIZATION_NICK)
# create background (text) and foreground (color markings)
bg = cv2.bitwise_and(text, text, mask = mask_inv)
fg = cv2.bitwise_and(image, image, mask = mask)
out = cv2.add(cv2.cvtColor(bg, cv2.COLOR_GRAY2BGR), fg)
如果您不需要顏色標記,您可以簡單地將灰度圖像二值化:
image = cv2.imread('mY7ep.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
text = cv2.ximgproc.niBlackThreshold(gray, 255, cv2.THRESH_BINARY, at_bs, -0.3, binarizationMethod=cv2.ximgproc.BINARIZATION_NICK)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.