Python + OpenCVで顔認識

OpenCVで画像処理を試してみたついでに、ドキュメントを斜め読みしていたら、顔認識に関するチュートリアル(OpenCV: Face Detection using Haar Cascades)があった。最近、人の顔を覚えられなくなってきているオレを助けてくれそ うなテクノロジーではある。

Haar Cascadesを用いた顔認識

この辺りの機械学習のことは詳しくは良く分からないんだけれど、簡単に言うと顔じゃない画像と顔画像を使ってHaar特徴量から顔を判別できるように訓練する。その結果として識別データができるんだけれど、識別データを効率的に使って識別する方法として、Cascade識別器というのが考案されていて、OpenCVの配布物の中に含まれているようだ。

MacのAnacondaの場合は「~/anaconda3/share/OpenCV/haarcascades」に、Windows版のAnacondaの場合には「Anaconda3\Library\etc\haarcascades」の中に入っている。

  • haarcascade_eye.xml ... 眼認識
  • haarcascade_frontalface_default.xml ... 顔認識
  • haarcascade_smile.xml ... 笑顔認識

とりあえず、これをコピーしておくか、コードの中でFullPathで明示的に指定する。今回はコピーしといた。

face_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml')

次に画像ファイルを読み込む。cv2.imread()は、第二引数に0を指定するとグレースケールモードで読み込んでくれるんだけれど、その機能は使わないで、imgとしてカラーで読み込んだ後で、cv2.cvtColor()を使ってグレースケールに変換したコピーを持つ。

グレースケール画像(gray)で顔認識をして座標を取得して、元のカラー画像(img)に加工するため、それぞれの形式の画像データが必要ということだ。

img = cv2.imread(file)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

画像の中で顔を探して、その顔の位置の座標を戻す。もう訓練済みの識別データに基づいて識別器を使うだけなので、たったの一行。

faces = face_cascade.detectMultiScale(gray, 1.3, 5)

顔を探すのはグレースケールに変換した画像(gray)の中で行なうんだけれど、その顔座標の位置に基づいて元のカラー画像(img)に、顔を囲む矩形を描画する。
x,yが矩形の左上のそれぞれx,y座標を示していて、w,hはそれぞれ幅と高さを示しているんだけれど、OpenCVで画像(img)中に長方形を描画する時には、左上のx,y座標と右下のx,y座標がそれぞれ必要なので、(x,y), (x+w,y+h)というように指定している。

for (x, y, w, h) in faces:
    cv2.rectangle(img, (x,y), (x+w, y+h), (255,0,0), 2)

最後に矩形を書きこんだ画像を表示するんだけれど、OpenCVのimread()で読み込んだカラー画像は何故かBGRの順にデータが保持されているが、今回、画像表示のために使うmatplotlibのpyplotではRGBの順にデータが保持されているという前提になっているので、plt.imshow()にデータを渡す際に、cv2.cvtColor(img, cv2.COLOR_BGR2RGB)で変換している。

plt.imshow( cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()

ちなみに、顔は複数あってもOKなように、for (x,y,w,h) in faces: のように受けているんだけれど、ちょうどいい感じの著作権とか肖像権がウヤムヤな集合写真みたいなのが無いので、試せないな。

眼認識もできる

さて、チュートリアルには、顔認識の後で眼認識をするサンプルも載っている。顔があったら眼があるよね、顔じゃないところには眼は無いよね、ということで、顔認識した矩形の中を対象に眼認識を走らせるように工夫されている。なるほどな。

faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
    cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    roi_gray = gray[y:y+h, x:x+w]
    roi_color = img[y:y+h, x:x+w]
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex,ey,ew,eh) in eyes:
        cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

問題は、「Haar特徴量に基づくCascade識別器」に関して、何も分からなくて、detectMultiScale()メソッドの引数の説明が全然理解できないことだったりする。

さらに問題なのは、自分でCascade識別器を作れるようになる気がしないことだな。

修正するなど

Excelのデータを読み込む( http://d.hatena.ne.jp/fukuit/20160828/1472395613 )として書いていた記事に間違いがあったので、修正。間違えてたのは、t検定のメソッド。

t,p = stats.ttest_rel(tokyo, kyoto)

と書いていたけれど、 ttest_rel() は対応のあるt検定だった。ここは、対応のないt検定をしなければならない。その場合は、ttest_ind()を使う。

t,p = stats.ttest_ind(tokyo, kyoto)

ちなみに、studentのt検定とWelchのt検定では、Welchの方法のほうがrobustだし、正規分布を仮定しなくてもいいので、この場合はWelchの方法で良いだろうと思う。

t,p = stats.ttest_ind(tokyo, kyoto, equal_var=False)

さて、ttest_ind()には、片側検定をするためのオプションがない。東京の方が低いという仮説を検定するので、まあこれは、t値が負の値になってp値が0.025以下になればOKだろう。OKだよね?
結果は、t値が-4.09874 で、 p値が0.00014なので、「東京のほうが低いとはいえない」という帰無仮説を棄却できることになった。

グラフ描画

せっかく、数値データをExcelで読み込んだので、グラフを描画したい。R ならggplot2を使うところで、もちろんpythonでもggplot2を使えるようなんだけれど、matplotlibを使うのが一般的なようだ。

以下のように修正する。

import xlrd
import os.path
import pandas as pd
import numpy as np
from scipy import stats
from matplotlib import pyplot as plt
%matplotlib inline 

xlfile = "data.xlsx"
if os.path.exists(xlfile):
    xls = xlrd.open_workbook(xlfile)
    sheet1 = xls.sheet_by_index(0)
    nrows = sheet1.nrows - 1
    ncols = sheet1.ncols
    data = np.zeros(ncols*nrows).reshape((nrows, ncols))
    date = []
    for r in range(1, nrows+1):
        for c in range(0, ncols):
            if c==0:
                d =  xlrd.xldate.xldate_as_datetime(sheet1.cell(r,c).value, xls.datemode)
                date.append(d)
            else:
                data[r-1,c] = sheet1.cell(r,c).value

    tokyo = data[:,1]
    kyoto = data[:,2]
    
    plt.plot(date, tokyo, label="Tokyo")
    plt.plot(date, kyoto, label="Kyoto")
    plt.legend()
    plt.show()

日付が重なっちゃって読みづらいな。

Excelデータを読み込む

ExcelデータをPythonで読み込みたい。anaconda search -t conda xls とかすると、いろんなパッケージがヒットするんだけれど、ソコではヒットしなかったxlrdというパッケージをまずは conda でインストールする

Excelデータの準備


京都に単身赴任中、「京都は暑いでしょう?」と何度も言われたので、ソレを検証してみよう。気象庁のサイトから、2016年7月の東京の最高気温と京都の最高気温のデータを取得して、Excelでまとめた。

Excelデータを読み込むコード

というワケで、見よう見まねで書いてみたコードがコレで、東京と京都の平均気温を計算して、表示する。numpyを使っているので、mean()するだけで、平均値を求められる。

import xlrd
import os.path
import numpy as np
xlfile = "test.xlsx"
if os.path.exists(xlfile):
    xls = xlrd.open_workbook(xlfile)
    sheet1 = xls.sheet_by_index(0)
    nrows = sheet1.nrows-1
    ncols = sheet1.ncols 
    data = np.zeros(ncols*nrows).reshape((nrows, ncols))
    for r in range(1, nrows):
        for c in range(0, ncols):
            data[r-1,c] = sheet1.cell(r,c).value
    tokyo = data[:,1]
    kyoto = data[:,2]
    msg = "Tokyo(mean): %.2f\nKyoto(mean): %.2f" % (tokyo.mean(), kyoto.mean())
    print(msg)

検定を実施

しかし、平均値をそれぞれ表示しても、東京と京都の気温差について語ることはできない。ココは有意水準 0.05 であるとして、t検定をしてみることにする。

scipyで簡単にt検定できた。ここは、京都のほうが暑いという仮説の検定をしたいので、本来は片側検定をすべきかな。とはいえ、p-value < 0.05となり、東京と京都の気温差はないという帰無仮説は棄却された。

とりあえず画像を読み込んでみるなど

画像ファイルの用意

まずは画像ファイルを用意しよう。こういう時は、Tiger.psかlenna.tiffを使うもんだと聞いたことがある。
というわけで、http://sipi.usc.edu/database/database.php?volume=misc からLennaの画像をダウンロードしておく。ちなみに「Scans of magazine pictures. Copyright belongs to original publisher or photographer.」となってるので、ホントは使用許諾は個別に取る必要があるみたいだぞ。

画像を読み込んで表示する

http://docs.opencv.org/3.1.0/d6/d00/tutorial_py_root.html を見よう見まねでやってみよう。

import numpy as np
import cv2
import os.path
lenna = "4.2.04.tiff"
if os.path.exists(lenna):
    img = cv2.imread("4.2.04.tiff")
    cv2.imshow("Lenna", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

画像表示するだけなんだけれど、numpy要るんスかね。

画像の2値化してみる

http://docs.opencv.org/trunk/d7/d4d/tutorial_py_thresholding.html を見ながら、Lennaの2値化をやってみる。コードの意味は、イマイチ分からない。

import cv2
import numpy as np
import os.path
from matplotlib import pyplot as plt
lenna = "4.2.04.tiff"
if os.path.exists(lenna):
    img = cv2.imread(lenna,0)
    img = cv2.medianBlur(img,5)
    ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
    th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2)
    th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
    titles = ['Original Image', 'Global Thresholding (v = 127)', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
    images = [img, th1, th2, th3]
    for i in range(0,4):
        plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
        plt.title(titles[i])
        plt.xticks([]),plt.yticks([])

    plt.show()

さらに、大津の2値化。

import cv2
import numpy as np
import os.path
from matplotlib import pyplot as plt
lenna = "4.2.04.tiff"
if os.path.exists(lenna):
    img = cv2.imread(lenna,0)
    img = cv2.medianBlur(img,5)
    ret,th1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    blur = cv2.GaussianBlur(img,(5,5),0)
    ret2,th2 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    titles = ['Original Image', 'Otsu Method', 'OTSU Method(w Gaussian Blur)']
    images = [img, th1, th2]
    for i in range(0,3):
        plt.subplot(1,3,i+1),plt.imshow(images[i],'gray')
        plt.title(titles[i])
        plt.xticks([]),plt.yticks([])

    plt.show()

これらのコードの意味を理解するのが、次の課題だ。

Anacondaをインストールする

とりあえず、Cygwin上でPython3を使えるようにして、さて、numpyだ、scipyだ、matplotだと思っていたんだけれど、同僚から「環境を統一しよう」と至極もっともな提案があり、彼がインストールしていたAnacondaをインストールすることになった。

というワケで、chocolateyでanaconda3をインストールした。

自宅でも学習できるように、自宅MacにもAnacondaをインストールすることにしよう。

brew を使えば簡単

Windows環境でchocolateyを使ったように、MacではHomeBrewのお世話になる。

% brew search anaconda
Caskroom/cask/anaconda                                       Caskroom/versions/anaconda2
% brew cask install anaconda
==> Migrating cached files to /Users/toshi/Library/Caches/Homebrew/Cask...
==> Caveats
To use anaconda, you may need to add the ~/anaconda3/bin directory
to your PATH environment variable, eg (for bash shell):

  export PATH=~/anaconda3/bin:"$PATH"

==> Satisfying dependencies
complete
==> Downloading https://repo.continuum.io/archive/Anaconda3-4.1.1-MacOSX-x86_64.sh

というワケで、export PATH=~/anaconda3/bin:$PATH を.zshrcに書いて、source ~/.zshrc しておく。

pyenv ? virtualenv ?

とりあえず、仮想環境を作る必要性って感じないんだよな。コレ、要るかな?要らないよね?ってことにする。

OpenCVのインストール

OpenCVをひとまず使えるようにする。pipを使うのかとおもいきや、condaを使うのな。

% anaconda search opencv
Using Anaconda Cloud api site https://api.anaconda.org
Run 'anaconda show <USER/PACKAGE>' to get more details:
Packages:
     Name                      |  Version | Package Types   | Platforms
     ------------------------- |   ------ | --------------- | ---------------
     ???/opencv                |    2.4.7 | conda           | win-64
                                          : http://opencv.org/
     Changxu/opencv3           | 3.1.0_dev | conda           | linux-64
     Definiter/opencv          |   2.4.12 | conda           | linux-64
     FlyEM/opencv              | 2.4.10.1 | conda           | linux-64, osx-64
                                          : Open source computer vision C++ library
     JaimeIvanCervantes/opencv | 2.4.9.99 | conda           | linux-64
     Nike/opencv-python        |    3.0.0 | pypi            |
                                          : OpenCV (Open Source Computer Vision) is a library of
    programming functions for real time computer vision.
     Nutastray/opencv          |          | []              |
     RahulJain/opencv          |   2.4.12 | conda           | linux-64, win-64, osx-64
     anaconda/opencv           |   2.4.10 | conda           | linux-64, linux-32, osx-64
     andywocky/opencv          |    2.4.9 | conda           | osx-64
     asmeurer/opencv           |    2.4.9 | conda           | osx-64
     bgreen-litl/opencv        |    2.4.9 | conda           | osx-64
     bwsprague/opencv          |  2.4.9.1 | conda           | osx-64
     clinicalgraphics/opencv   |  2.4.9.1 | conda           | linux-64, win-32, win-64, linux-32, osx-64
     conda-forge/opencv        |   2.4.12 | conda           | linux-64, win-32, win-64, osx-64
                                          : Computer vision and machine learning software library.
     conda-team/protoci-opencv |          | []              |
     csfoo/opencv              |   2.4.10 | conda           | linux-64
     derickl/opencv            |   2.4.10 | conda           | osx-64
     dhaneshr/opencv           |   2.4.13 | conda           | linux-64
     erik/opencv               |    2.4.9 | conda           | linux-64, osx-64
     hadim/opencv              |    3.0.0 | conda           | linux-64
     hovren/opencv             |    3.0.0 | conda           | linux-64
     hyperion/opencv           | 2.4.10.1 | conda           | linux-64
                                          : Llibrary for computer vision
     ijstokes/opencv           |   2.4.11 | conda           | osx-64
     jakirkham/opencv          |    3.1.0 | conda           | osx-64
     janc/opencv               |   2.4.12 | conda           | osx-64
                                          : with ffmpeg
     janc/opencv3              |    3.1.0 | conda           | osx-64
                                          : with ffmpeg and opencl
     jjhelmus/opencv           |   2.4.12 | conda           | osx-64
                                          : http://opencv.org/
     jlaura/OpenCV3            |    3.1.0 | conda           | linux-64, osx-64
                                          : OpenCV 3.0.0 with the optional contrib modules
     jmargeta/opencv           |    2.4.7 | conda           | win-64
                                          : http://opencv.org/
     joschka_zj/opencv         |   2.4.11 | conda           | win-64
                                          : OpenCV library
     jqscali/opencv3           |    3.0.0 | conda           | linux-64
     kangyounglee87/opencv     |   2.4.11 | conda           | linux-64
     lbernard/opencv3          |    3.1.0 | conda           | linux-64
     lebedov/opencv            |   2.4.11 | conda           | linux-64
     litl-rnd/opencv           |    2.4.9 | conda           | osx-64
     memex/opencv              |    3.0.0 | conda           | linux-64, win-64, osx-64
     menpo/opencv              |   2.4.11 | conda           | linux-64, win-32, win-64, linux-32, osx-64
     menpo/opencv3             |    3.1.0 | conda           | linux-64, win-32, win-64, osx-64
     mizvladimir/opencvtutorial_imageprocessinginopencv | 2016.01.03.2031 | ipynb           |
                                          : IPython notebook
     msarahan/opencv           |    3.1.0 | conda           | linux-64, win-32, win-64, linux-32, osx-64
     onlyjus/opencv            |    2.4.7 | conda           | win-64
                                          : http://opencv.org/
     osgeo/opencv              |    2.4.7 | conda           | linux-64, osx-64
     patricksnape/opencv       |   2.4.11 | conda           | linux-64, osx-64
     patricksnape/opencv-gpu   |  2.4.9.1 | conda           | linux-64
     phhuang/opencv            |   2.4.10 | conda           | linux-64
                                          : OpenCV compiled with ffmpeg.
     poppy-project/opencv      |    3.1.0 | conda           | linux-armv7l
     poppy-project/opencv3     |    3.1.0 | conda           | linux-armv7l
     prkrekel/opencv           |  2.4.9.1 | conda           | linux-64, win-32, win-64, linux-32, osx-64
     pypi/ctypes-opencv        |          | []              |
                                          : ctypes-opencv - A Python wrapper for OpenCV using ctypes
     pypi/opencv-cython        |          | []              |
                                          : An alternative OpenCV wrapper
     pypi/opencv_engine        |    1.0.0 | pypi            |
                                          : OpenCV imaging engine for thumbor.
     pypi/opencv_helpers       |      0.1 | pypi            |
                                          : Helper functions for opencv
     pypi/pyopencv             | 2.1.0.wr1.0.0 | pypi            |
                                          : PyOpenCV - A Python wrapper for OpenCV 2.x using Boost.Python and NumPy
     rsignell/opencv-python    |    2.4.9 | conda           | win-32
     salilab/opencv-nopython   |    2.4.9 | conda           | linux-64, win-32, win-64, linux-32, osx-64
                                          : opencv package built without Python (for Python 3)
     santiavenda2/opencv       | 2016.05.08.2120 | conda, env      | linux-32
     sean/opencv               |          | []              |
     shariqiqbal2810/opencv    |   2.4.11 | conda           | osx-64
     shiquanwang/opencv        | 3.0.0beta_28_g3234860 | conda           | linux-64
     sotera/opencv             |   2.4.11 | conda           | linux-64
     sotte/opencv_gtk          |    2.4.9 | conda           | linux-64
     stuarteberg/opencv        |          | conda           | linux-64
                                          : Open source computer vision C++ library
     tianzhou2011/opencv3      |    3.1.0 | conda           | linux-64
     timurbagautdinov/opencv   |   2.4.11 | conda           | linux-64
     tofighi/opencv3           |    3.1.0 | conda           | osx-64
     trax/numpy_for_opencv     |    1.9.3 | conda           | linux-64
     trax/opencv3              |    3.0.0 | conda           | linux-64
     trax/opencv3_gtk          |    3.0.0 | conda           | linux-64
     trax/opencv_gtk_numpy_1_8 |   2.4.10 | conda           | linux-64
     trung/opencv              |   2.4.11 | conda           | linux-64, osx-64
     trung/opencv3             |    3.1.0 | conda           | linux-64, osx-64
     tsc/opencv                |    2.4.9 | conda           | osx-64
     ver228/opencv             |    2.4.9 | conda           | osx-64
     ver228/opencv3            |    3.1.0 | conda           | linux-64, win-64
     wheeler-microfluidics/opencv-helpers |      1.1 | conda           | win-32
     willyd/opencv             |    3.1.0 | conda           | win-64
Found 77 packages

めっちゃあるやん。この中から、osx-64になってて、比較的バージョンが新しそうなヤツを選ぶんやな。

よく分からないけれど、どこかのWebサイトで見たmenpo/opencv3をインストールすることにしよう。

% anaconda show menpo/opencv3
Using Anaconda Cloud api site https://api.anaconda.org
Name:    opencv3
Summary:
Access:  public
Package Types:  conda
Versions:
   + 3.0.0
   + 3.1.0
 
To install this package with conda run:
     conda install --channel https://conda.anaconda.org/menpo opencv3
% 
% conda install --channel https://conda.anaconda.org/menpo opencv3
Fetching package metadata .........
Solving package specifications: ..........

Package plan for installation in environment /Users/toshi/anaconda3:

The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    tbb-4.3_20141023           |                0         1.6 MB  menpo
    conda-env-2.5.2            |           py35_0          27 KB
    conda-4.1.11               |           py35_0         204 KB
    opencv3-3.1.0              |           py35_0        37.3 MB  menpo
    ------------------------------------------------------------
                                           Total:        39.1 MB

The following NEW packages will be INSTALLED:

    opencv3:   3.1.0-py35_0   menpo
    tbb:       4.3_20141023-0 menpo

The following packages will be UPDATED:

    conda:     4.1.6-py35_0         --> 4.1.11-py35_0
    conda-env: 2.5.1-py35_0         --> 2.5.2-py35_0

Proceed ([y]/n)? 

さて、opencvを使えるようになってみるのは、明日のことだな。

ところで、こういうのって、qiita.comとかに書いとくと良いんだろうか。

Cygwin環境にPythonをインストールしてみる

仕事の関係で画処理をすることになったので、ImageJのマクロで頑張ってきた。
でも、なんだかんだでPythonで画処理をすることになった。仕事で使っているのはWindowsなので、まずはCygwin上で環境を整えようと思う。

pythonのバージョンは2にするの? 3にするの?

いろんなWebサイトを見ると、「version 3にすると対応してないライブラリがあるし、ノウハウが書いてあるサイトもversion 2がベースになっていることが多いから、2.7系列にしとけ」とか書いてあったりする。

ちょっと前にGAE/pyをイジってた時は、python 2.5にするか2.7にするか?的なことを考えてたワケだけれど、もうさすがに2.7は無いだろと思って、version3系列をインストールすることにした。

Cygwinのsetup-x86_64.exeを使ってpythonをインストールすると2.7になるんだけれど、python3をちゃんと選択すれば、3.4.3がインストールされる。

pip ?

パッケージ管理システムとして、setuptoolsだのeasy_installだのpipだのという単語は知ってるんだけど、具体的にはどうなってるのかよくわかってない。

なんかインストールせなあかんのやな、、、と思って少し調べたら、python3.4.3からはpipが標準的に使えるようになっているらしい。

% python3 -m ensurepip
Ignoring indexes: https://pypi.python.org/simple
Collecting setuptools
Collecting pip
Installing collected packages: pip, setuptools
 
Successfully installed pip-6.0.8 setuptools-12.0.5
% 

これでpipを使えるようになったところで、早速使ってみようとすると、以下のような警告が表示された。

 You are using pip version 6.0.8, however version 8.1.2 is available.
 You should consider upgrading via the 'pip install --upgrade pip' command.

なるほど。

% /usr/bin/pip3 install --upgrade pip
You are using pip version 6.0.8, however version 8.1.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting pip from https://pypi.python.org/packages/9c/32/004ce0852e0a127f07f358b715015763273799bd798956fa930814b60f39/pip-8.1.2-py2.py3-none-any.whl#md5=0570520434c5b600d89ec95393b2650b
  Downloading pip-8.1.2-py2.py3-none-any.whl (1.2MB)
    100% |################################| 1.2MB 525kB/s
Installing collected packages: pip
  Found existing installation: pip 6.0.8
    Uninstalling pip-6.0.8:
      Successfully uninstalled pip-6.0.8
 
Successfully installed pip-8.1.2

画処理準備

PILを使うか、OpenCVを使うか、といったところだけれど、ひとまず今日はここまで。

震央plot続き

4月1日から4月29日までの震度を日本全国の単位でplotしてみて、日ごとにanimated gifにしてみた。

コレを見ると、日本という単位では、毎日どこかしらで、それなりのmagnitudeの地震が観測されている。備えは大切だ言われる所以だ。

さて、熊本に着目してみると、こうなる。

4月前半を見ている限り、あれほどの大地震が襲ってくるとはとても予測できない。日常が、いきなり非日常に変わってしまったんだということがよく分かる。