第5章 画像処理


序文

この章では、画像ピラミッド、画像輪郭テンプレート抽出、ヒストグラム、画像フーリエ変換などの画像処理に関連する内容について説明します。

1. イメージピラミッド

  • 意味:画像ピラミッドは、画像処理とコンピューター ビジョンで使用される技術です。これは、各画像が前の画像よりも解像度が低い画像のコレクションであり、ピラミッド構造を形成しています。これらの画像は、同じ画像の異なる解像度バージョンから生成することも、異なる画像間でスキャンして縮小することもできます。
  • 機能:画像強化では、画像を異なる解像度の一連の画像に分解し、各解像度レベルの画像を処理して、最終的に強化画像に合成します。画像検出では、スケール不変の物体の検出にピラミッド技術を使用できます。オブジェクト追跡では、さまざまなスケールでオブジェクトを検索できます。
    ここに画像の説明を挿入

1. ガウスピラミッド

  • ダウンサンプリング (画像の縮小):
    1. ガウスフィルタリングが最初に実行されます
    2. 偶数番号の行と列を削除する
  • アップサンプル (画像を拡大します):
    1. 偶数行、列をゼロで埋める
      [ 10 30 56 96 ] ⇒ [ 10 0 30 0 0 0 0 0 0 56 0 96 0 0 0 0 0 ] \begin{bmatrix} 10& 30\\ 56&96\end{bmatrix}\Rightarrow \ begin{bmatrix} 10 & 0 & 30 & 0\\ 0& 0 & 0 & 0\\ 56& 0& 96 &0 \\ 0& 0& 0&0\end{bmatrix}[10563096 10056000003009600000
    2. 拡大した画像に対してガウス畳み込みを実行し、ゼロ値を埋めることができるようにします。
# 向上采样
cv2.pyrUp(src[, dst[, dstsize[, borderType]]]) -> dst
# 向下采样
cv2.pyrDown(src[, dst[, dstsize[, borderType]]]) -> dst

2. ラプラスのピラミッド

I i + 1 = I i − P yr Up ( pyr D own ( I i ) ) I_{i+1} = I_i - PyrUp(pyrDown(I_i))+ 1=私はピルアップ(ピルダウン( I _ _ _ _ _ _私は))
上記の式を実行して各レイヤーの画像を取得します。

ラプラシアン ピラミッドとガウス ピラミッドは画像ピラミッドの ​​2 つの重要な概念であり、次のような違いがあります。

  1. アルゴリズムのステップは異なります。ガウス ピラミッドは、元の画像を継続的にダウンサンプリング (ダウンサンプリング) し、ガウス フィルター処理を行うことによって取得され、各ダウンサンプリングで画像のサイズが半分になります。ラプラシアン ピラミッドは、対応する低解像度画像を連続的にアップサンプリング (拡大) し、ガウス ピラミッドから減算することによって取得されます。

  2. さまざまなピラミッドの目的: ガウス ピラミッドは主に画像のダウンサンプリング (縮小) とスケール空間分析に使用され、SIFT、SURF アルゴリズムなどの画像のスケール不変の特徴記述に使用できます。ラプラシアン ピラミッドは主に画像強調、エッジ検出、画像融合に使用されます。

  3. ピラミッドのレイヤーとサイズ: ガウス ピラミッドのレイヤーの数は元の画像のサイズに関連しており、サイズが大きいほど、ガウス ピラミッドのレイヤーの数が多くなります。また、ラプラシアン ピラミッドはガウス ピラミッドから派生したものであるため、通常はガウス ピラミッドと同じサイズになります。

  4. 局所特徴情報: 可逆性と単一スケール不変性は便利ですが、局所特徴を説明するためにのみ使用される場合は十分な精度が得られない可能性があります。したがって、ラプラシアン ピラミッドは通常、ガウス ピラミッドよりも豊富な局所特徴情報を提供できます。

したがって、さまざまなアプリケーションシナリオに応じて、ガウスピラミッドやラプラシアンピラミッドなどの適切なピラミッド構造を選択して画像を処理できます。

2. イメージ概要

1. 輪郭抽出

contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

の:

  • image: 入力画像はバイナリ画像である必要があり、各ピクセルの値は 0 または 255 で、前景色と背景の 2 色を表します。
  • mode: 輪郭取得モード。これは列挙値であり、その値の範囲には次のものが含まれます。
    • cv2.RETR_EXTERNAL: 最も外側の輪郭のみを検出します。つまり、エッジ輪郭のみを返します。
    • cv2.RETR_LIST: すべての輪郭を検出し、その完全なリストを返します。
    • cv2.RETR_CCOMP: すべての輪郭を検出しますが、2 レベルの輪郭構造、つまり外側輪郭と内側輪郭のみを返します。
    • cv2.RETR_TREE: すべての輪郭を検出し、完全な輪郭ツリー構造を返します。
  • method: 輪郭近似法。列挙値であり、値の範囲には次のものが含まれます。
    • cv2.CHAIN_APPROX_NONE: すべての輪郭点を保存し、各点の座標 (x, y) を保存します。
    • cv2.CHAIN_APPROX_SIMPLE: 輪郭の端点のみを保持し、その座標を保存するだけです。たとえば、長方形の輪郭の場合は 4 点の座標のみが必要です。
  • contours: 出力パラメータ。検出された輪郭を返します。各輪郭はピクセル座標で表される Numpy 配列です。
  • hierarchy: 出力パラメータ。輪郭の階層関係を返します。各輪郭は 4 つの値で表されます(父级轮廓编号,下一级轮廓编号,第一个子级轮廓编号,前一个兄弟轮廓编号)
    階層構造の理解

2. 等高線描画

cv2.drawContours()OpenCVが提供する画像に輪郭を描画できる機能です。

この関数の構文は次のとおりです。

cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

パラメータは次のように説明されます。

  • image:輪郭を描く画像です。
  • contourscv2.findContours():関数を通じて取得できる輪郭点セットからなるリスト。このパラメータには、単一の輪郭 (ポイント コレクション) または複数の輪郭のリストを指定できます。
  • contourIdx:描画する輪郭の番号を指定します。負の場合は、すべての輪郭を描画することを意味します。
  • color: アウトラインの色。RGB タプルまたは BGR タプルを使用できます。
  • thickness: 等高線の太さ、デフォルト値は 1 です。
  • lineType: 回線タイプ。デフォルト値は 8 接続 (つまり cv2.LINE_8) ですが、4 接続 (つまり cv2.LINE_4) または CV_AA に設定することもできます。
  • hierarchy: 輪郭レベル情報、オプションのパラメータ。
  • maxLevel: 描画できる輪郭の最大レベル。オプションのパラメータ。
  • offset: 輪郭計算用のオフセット、オプションのパラメータ。

3. 輪郭の特徴

OpenCV には、画像内の輪郭について、これらの輪郭を記述および分析するために使用できる機能が多数あります。主なプロファイル機能の一部を以下に示します。

  1. 輪郭領域: 輪郭曲線に含まれる領域のサイズ。cv2.contourArea()関数を使用して計算できます。

  2. 輪郭周囲長: 関数を使用して計算できる輪郭曲線の長さcv2.arcLength()

  3. cv2.approxPolyDP()輪郭近似:関数で処理できる輪郭点の数を減らすことで輪郭形状を近似します。

  4. 輪郭重心:輪郭曲線に含まれる領域の重心点座標。cv2.moments()関数で計算できます。

  5. 輪郭方向: 輪郭曲線の方向。関数cv2.fitEllipse()または関数cv2.minAreaRect()を使用してそれぞれ楕円または長方形を当てはめることによって計算できます。

  6. 輪郭凸包: 輪郭曲線のすべての点を含む凸形状。cv2.convexHull()関数で計算できます。

  7. 輪郭欠陥: 凸包と輪郭曲線の間のギャップはcv2.convexityDefects()関数で計算できます。

これらの輪郭特徴を組み合わせて使用​​して、画像内の輪郭形状と特徴を分析できます。実際のアプリケーションでは、輪郭特徴は物体検出、画像分類、画像認識などのタスクによく使用されます。

4. 輪郭近似

  • 原理: ここに画像の説明を挿入
    まず 2 つの点 A と B を結び、次にこの点から直線 AB までの距離が最大になるような円弧 AB 上の点を見つけます。この点を C として記録し、d が の場合は距離を d として記録します。指定値未満の場合は、円弧 AB を直線 AB に置き換えます。それ以外の場合は、C を中点として、円弧 AC と円弧 CB の近似をそれぞれ判断します。

OpenCVでは、cv2.approxPolyDP()この機能により輪郭を近似して輪郭点の数を減らし、輪郭曲線を単純化することができ、画像処理の効率を向上させることができます。この関数の構文は次のとおりです。

cv2.approxPolyDP(curve, epsilon, closed[, approxCurve])

パラメータは次のように説明されます。

  • curve: 入力輪郭。通常は点のリストまたは Numpy 配列です。
  • epsilon: 近似の程度、つまり輪郭に対する最大誤差を指定します。指定された距離がイプシロンより小さい場合、点は同じ曲線上にあるとみなされます。
  • closed: 閉じた曲線かどうかを指定します。 Yes の場合はTrue曲線が閉じていることを意味し、それ以外の場合は開いた曲線を意味します。
  • approxCurve: 出力への近似輪郭。numpy 配列または空のオブジェクトにすることができます。出力配列が指定されていない場合、関数は輪郭を近似する座標点の配列を返します。

この関数の戻り値は近似輪郭の座標点を表し、近似曲線上の点の数は出力配列のサイズによって決まります。epsilonの値は多くの要因の影響を受けるため、特定の状況に応じて設定する必要があります。

近似処理の効果は調整パラメータに影響されることが多く、epsilon設定が小さすぎて処理が過剰になると重要な輪郭情報が失われる可能性があり、設定がepsilon大きすぎると輪郭情報が残りすぎて負荷が増加する可能性があります。計算量が多くなり、輪郭の誤検出や見逃しなどの問題が発生する可能性があります。したがって、輪郭近似を実行する場合、最良の処理効果を達成するには、特定の状況に応じてパラメータを調整する必要があります。

5. 輪郭マーキング

  • 機能:輪郭を形状 (長方形、円など) でマークします。
# 背景画布
canvabg = img.copy()
# 获取轮廓
cnt0 = contours[0]
# 矩形边框
startx,starty,width,height = cv2.boundingRect(cnt0)
cv2.rectangle(canvabg,(startx,starty),(startx + width,starty + height),(0,255,0),2)
# 获取轮廓
cnt1 = contours[2]
# 圆圈外框
(cx,cy),radius = cv2.minEnclosingCircle(cnt1)
cv2.circle(canvabg,(int(cx),int(cy)),int(radius),(255,0,0),2)

ここに画像の説明を挿入

3. テンプレートマッチング

  • アイデア:テンプレート イメージをコンボリューション カーネルとして使用し、一致したイメージでコンボリューション演算を実行し、特定のマッチングアルゴリズム畳み込み演算の各ステップの信頼レベルを計算し、信頼レベルに従って、一致した画像内のテンプレート画像の位置を決定します。

OpenCVではcv2.matchTemplate()画像マッチングの機能を関数を利用して実現できます。画像マッチングとは、画像内の特定の関心領域 (通常はテンプレート画像) の位置と数を見つけることを指します。

cv2.matchTemplate()関数の構文は次のとおりです。

cv2.matchTemplate(image, templ, method[, result[, mask]]) → result

パラメータは次のように説明されます。

  • image: 入力画像は 8 ビットまたは 32 ビット浮動小数点のグレースケール画像である必要があります。
  • templ: テンプレート画像、入力画像内で検索する画像領域。入力画像と同じデータ型とチャネル数を持ちます。
  • method:
    • 二乗差分マッチング ( cv2.TM_SQDIFF): このマッチング方法では、入力画像とテンプレート画像のピクセルの差の二乗を順番に比較し、差分の合計を返します。一致結果が小さいほど一致度が高いことを示す。

    • 正規化二乗差マッチング ( cv2.TM_SQDIFF_NORMED): このマッチング方法は二乗差マッチング方法と似ていますが、マッチング結果は正規化されます。つまり、マッチング結果が小さいほどマッチング度は高くなります。

    • 相関マッチング ( cv2.TM_CCORR): このマッチング方法は、入力画像とテンプレート画像に対して相互相関演算を実行し、相関係数の最大値を返します。一致結果が大きいほど一致度が高いことを示す。

    • 正規化された関連マッチング ( cv2.TM_CCORR_NORMED): このマッチング方法は関連マッチング方法と似ていますが、マッチング結果が正規化されています。つまり、マッチング結果が大きいほど一致度が高くなります。

    • 係数マッチング ( cv2.TM_CCOEFF): 入力画像とテンプレート画像の相関係数を計算し、相関係数画像から最大値を求めるマッチング方法です。一致結果が大きいほど一致度が高いことを示す。

    • 正規化された係数のマッチング ( cv2.TM_CCOEFF NORMED): 正規化された相関係数を計算します。計算された値が 1 に近いほど、関連性が高くなります。

  • result: 一致した結果 通常、このパラメータを指定する必要はなく、関数は自動的に作成されます。そのサイズは、入力イメージのサイズからテンプレート イメージのサイズに 1 を加えたもので、2 次元配列になります。
  • mask: マスク、指定した場合、テンプレート マッチングはマスクされた領域内でのみ実行されます。
import numpy as np
import cv2
import matplotlib.pyplot as plt


img = cv2.imread("F:/MyOpenCV/ai.jpg")
imgTmp = cv2.imread("F:/MyOpenCV/aitemp.jpg")

result = cv2.matchTemplate(img, imgTmp, cv2.TM_SQDIFF_NORMED)
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(result)
x, y = minLoc
h, w, t = imgTmp.shape
cv2.rectangle(img, minLoc, (x + w, y + h), (255, 0, 0), 2)

cv2.imshow("img", img)
cv2.imshow("imgsim", imgTmp)
cv2.waitKey(0)
cv2.destroyAllWindows()

ここに画像の説明を挿入

4. ヒストグラム

1. コントラスト

  • 定義:コントラストは、画像の最も明るい領域と最も暗い領域の差、つまり、白と黒の違いの程度を表す尺度です。デジタル画像処理では、コントラストは、通常、画像内のピクセルの明るさと色の値を調整することによって、画像の明暗を調整するために使用されます。コントラスト比が高いと画像がより鮮明で明るくなりますが、コントラスト比が低いと画像が柔らかく見えたり、ぼやけたり、区別できなくなったりすることがあります。

2. ヒストグラムを描く

ここに画像の説明を挿入
ヒストグラムの横軸はピクセル チャネル値の値範囲、縦軸は値の出現数です。

cv2.calcHist()グレースケール イメージのヒストグラムの計算に使用できます。また、カラー イメージのヒストグラムの計算にも使用できます。

cv2.calcHist()構文は次のとおりです。

hist = cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])

パラメータは次のように説明されます。

  • images: numpy 配列として提供される入力画像。グレースケール イメージのヒストグラムを計算する場合、 の次元imagesは2 次元である必要があり、カラー イメージの場合は 3 次元である必要があり、3 番目の次元はイメージのカラー チャネルを表します。関数に渡される画像はリストである必要があります。単一の画像のみを使用している場合でも、画像をリスト内でラップしてください。
  • channels: カウントするカラー チャネルのインデックスのリスト。グレースケール イメージの場合、このパラメータは である必要があります[0]。カラー イメージの場合、通常は 3 つのカラー チャネル[0, 1, 2]を表します。
  • mask: ヒストグラム計算に参加するピクセル位置を指定するオプションのマスク イメージ。マスク画像内の対応する位置のピクセル値がゼロ以外の場合にのみ、この位置のピクセルがヒストグラム計算に含まれます。
  • histSize: ヒストグラム内のビンの数、つまり間隔の数。このパラメータはリストである必要があり、各要素はチャネルのビンの数を表します。
  • ranges: ヒストグラムのピクセル値範囲、つまり区間範囲。パラメータはリストである必要があり、各要素はチャネルのピクセル値の範囲を表します。
  • hist: オプションの出力ヒストグラム配列オブジェクト。
  • accumulate: オプションの蓄積フラグ。

cv2.calcHist()の戻り値は、計算されたヒストグラムを表す numpy 配列です。グレースケール イメージの場合は 1 次元配列が返され、カラー イメージの場合は 3 次元配列が返され、各次元は BGR の 3 チャネルのヒストグラムを表します。

img = cv2.imread("F:/MyOpenCV/hello.jpg")
b, g, r = cv2.split(img)
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

histGray = cv2.calcHist([imgGray], [0], None, [256], [0, 256])

# 绘制直方图
plt.plot(histGray)
plt.xlim([0, 256])
plt.xlabel("灰度值")
plt.ylabel("像素数量")
plt.show()

ここに画像の説明を挿入

注: matplotlib メソッドを使用することもできます。plt.hist(data, histSize)この場合、データはヒストグラムの 1 次元配列であるため、画像データはravel関数を呼び出します。

3. イコライゼーション

3.1 理論

  • 目的:元の画像を変換して、グレー ヒストグラム内のグレー値が均一に分布している新しい画像を取得します。画像内のピクセル数が多いグレー レベルは引き伸ばされ、ピクセル数が少ないグレー レベルは縮小されます。鮮明な画像の目的を達成するために。理想的な状況は、変換後のピクセルのグレー レベル確率がまったく同じであることですが、実際にはそれほど平均的になることはできません。
    ここに画像の説明を挿入

3.2 コード

cv2.equalizeHist(src:image[, dst]) -> dst:image

ここに画像の説明を挿入

4. クラッシュ

  • ヒストグラム等化問題:

    • 明るい領域がより明るくなり、暗い領域がより暗くなり、結果としてディテールが失われるグローバル効果。
    • ノイズの増幅につながる可能性があります。
  • アイデア:画像を分割し、各部分を個別に均等化し、各部分のヒストグラムの確率分布を制限します。

  • アルゴリズムの実装:

    1. 画像のブロック
    2. 各ブロックの中心点を見つける
    3. 各ブロックのグレーヒストグラムを個別に計算し、しきい値を制限します
    4. 各ブロックのヒストグラム分布が得られた後、ヒストグラム等化アルゴリズムに従って各ブロックの中心点が等化されます。計算を高速化するために、中心点のみを等化することが行われます。
    5. 中心点の均等化されたグレー値に従って、画像ブロックの残りのピクセルのグレー値が差分アルゴリズムによって計算されます。
  • コード:

    # 生成自适应均衡化算法 
    # clipLimit :阈值,1 表示不做限制。值越大,对比度越大
    # tileGridSize:如何拆分图像
    clahe = cv2.createCLAHE([, clipLimit[, tileGridSize]]) -> retval
    # 对像素通道进行自适应均值化处理
    dst = clahe.apply(src)
    
    

    cv2.createCLAHE 関数は、clipLimit、tileGridSize、tileGridSizeX (tileGridSize の代わり) という 3 つのパラメータを受け入れます。

    • ClipLimit: コントラスト レベルを維持するための制限値。値が小さいほど、維持されるコントラスト レベルは高くなります。
    • tileGridSize: 画像を分割する長方形のブロックのサイズ (ピクセル単位)。このパラメータは奇数である必要があります。tileGridSizeX パラメーターで指定されている場合、このパラメーターを入力する必要はありません。
    • tileGridSizeX: tileGridSize と同じで、長方形ブロックのサイズを指定するために使用されます。

五、画像フーリエ変換

5.1 正弦平面波

ここに画像の説明を挿入

  • 直感的な定義: 1 次元のサイン曲線を縦方向 1 方向に引き伸ばして 3 次元波形を取得し、波形の振幅変化を 2 次元平面で表し、2 次元平面波をグレースケール画像に描画します。 , したがって、山は白255、谷は黒0で、中間はグレースケール遷移になります。
  • 数学パラメータ:
    • 正弦波: 周波数 w、振幅 A、位相φ \varphiファイ
    • 伸長方向: 2 次元座標では、ベクトルはn → = ( μ , v ) \overrightarrow{n} = (\mu, v)と書くことができます。n =( m v )

5.2 2次元フーリエ変換

  • 考え方: 2 次元フーリエ変換では、2 次元データは無数の数から正弦平面波構成されていると考えられます。
    ここに画像の説明を挿入
  • 離散フーリエ変換の公式:
    F ( u , v ) = 1 MN ∑ x = 0 M − 1 ∑ y = 0 N − 1 f ( x , y ) e − i 2 π ( ux M + vy N ) F( u, v) = \frac{1}{MN}\sum_{x=0}^{M-1}\sum_{y=0}^{N-1}f(x,y)e^{-i2 \pi (\frac{ux}{M}+\frac{vy}{N})}F ( u ,v )=ミネソタ州1x = 0M 1y = 0N 1f ( x ,i 2 π (Mうーん+Nvy _
  • パラメータの説明:
    ここに画像の説明を挿入

5.3 2次元フーリエ変換結果F ( u , v ) F(u, v)F ( u ,v )

  • (u, v) ストレッチ方向のベクトル
  • w = u 2 + v 2 w = \sqrt{u^2 + v^2}w=あなた2+v2 ベクトルの大きさは正弦波の周波数を表します
  • F(u, v): 正弦波の振幅 A と位相φ \varphiを意味する複素数φ . 詳細については、上記の詳細な説明を参照してください。

5.4 フーリエ変換の実現

OpenCV はdft(src:np.float[, dst[, flags[, nonzeroRows]]]) -> dstフーリエ変換を提供します。パラメータの意味は次のとおりです。

  • src: 入力シングルチャンネル画像。浮動小数点型である必要があります。
  • dst: 結果を複数形で出力します。サイズは以下とsrc一致します。
  • flagscv2.DFT_COMPLEX_OUTPUT: 変換操作の追加オプション。通常、出力が複雑であることを示すように設定できます。
  • nonzeroRows: 入力画像のサイズが 2 のべき乗ではない場合、変換中心を手動で指定する必要があります (入力画像のサイズが偶数の場合、デフォルトの中心は画像の中心になります。それ以外の場合、中心は左上隅になります)。
  • n: 変換のサイズを指定するオプションのパラメータ。通常はsrc
  • 戻り値は yes で双通道、最初のチャネルは実数部、2 番目のチャネルは虚数部です。

ここに画像の説明を挿入

注: 離散フーリエ変換は共役対称性したがって、4 分の 1 だけが有効で、もう 1 つは反転されます。
ここに画像の説明を挿入

  • スペクトログラムの一元化:
    フィルタリング操作に便利です。
    # 频谱中心化
    shiftA = np.fft.fftshift(A)
    

ここに画像の説明を挿入

5.5 フーリエフィルタリング

  • アイデア:
    1. 画像のグレースケールに対してフーリエ変換を実行して、周波数領域の結果を取得します。
    2. 削除する周波数に対応するフーリエ変換結果をすべて0+i0とする
    3. 修正されたフーリエ変換結果に対して逆フーリエ変換を実行します。

5.5.1 ローパスフィルタリング

低周波部分の結果をすべてゼロに設定します。

import numpy as np
import cv2
import matplotlib.pyplot as plt


img = cv2.imread("F:/MyOpenCV/ai.jpg")
yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
yfloat = np.float32(yuv[:, :, 0])  # 其实就是取了灰度图

dft = cv2.dft(yfloat, flags=cv2.DFT_COMPLEX_OUTPUT)  # 生成频谱图
dftShift = np.fft.fftshift(dft)  # 中心化

centerRow = int(dftShift.shape[0] / 2)  # 宽的中心
centerCol = int(dftShift.shape[1] / 2)  # 列的中心

mask = np.zeros(dftShift.shape, dtype=np.uint8)  # 构造一个掩膜
mask[centerRow - 30 : centerRow + 30, centerCol - 30 : centerCol + 30, :] = 1
dftShift = dftShift * mask  # 按位乘

dft = np.fft.ifftshift(dftShift)  # 先反中心化
idft = cv2.idft(dft)  # 再反傅里叶

iyDft = cv2.magnitude(idft[:, :, 0], idft[:, :, 1])  # 转为实数
iy = np.uint8(iyDft / iyDft.max() * 255)  # 映射

yuv[:, :, 0] = iy
imgRes = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR)


cv2.imshow("imgRes", imgRes)


cv2.waitKey(0)
cv2.destroyAllWindows()

ここに画像の説明を挿入

5.5.2 ハイパスフィルタリング

ローパスと同様にマスクを変更するだけで効果は以下の通り(今度グレースケール使うのはちょっと怖い)
ここに画像の説明を挿入

要約する

最近、研究室のプロジェクトが忙しくて、この記事は少し遅くなってしまいましたが、この2日で終わらせる予定です。

おすすめ

転載: blog.csdn.net/zhanghongbin159/article/details/130607590