LoginSignup
3
1

More than 5 years have passed since last update.

graphcut - networkx

Posted at

networkxを用いたgraphcut

guraphcutの記事が見当たらなかったので書いてみました。
data項は大津の閾値判定法から前景らしさ、背景らしさを決定し
smooth項は上下左右の画素値の差を元に決定しました。

graphcut.py
import networkx as nx
from scipy.misc import imread
import numpy as np
import math
import matplotlib.pyplot as plt
import cv2

lumda = 1000
k = 0.001


# 大津の手法
def threshold_otsu(gray, min_value=0, max_value=255):
    # ヒストグラムの算出
    hist = [np.sum(gray == i) for i in range(256)]

    s_max = (0, -10)

    for th in range(256):

        # クラス1とクラス2の画素数を計算
        n1 = sum(hist[:th])
        n2 = sum(hist[th:])

        # クラス1とクラス2の画素値の平均を計算
        if n1 == 0:
            mu1 = 0
        else:
            mu1 = sum([i * hist[i] for i in range(0, th)]) / n1
        if n2 == 0:
            mu2 = 0
        else:
            mu2 = sum([i * hist[i] for i in range(th, 256)]) / n2

        # クラス間分散の分子を計算
        s = n1 * n2 * (mu1 - mu2) ** 2

        # クラス間分散の分子が最大のとき、クラス間分散の分子と閾値を記録
        if s > s_max[1]:
            s_max = (th, s)

    # クラス間分散が最大のときの閾値を取得
    t = s_max[0]
    print(t)

    return t


def add_tedges(g, t, img):
    row = img.shape[0]
    column = img.shape[1]
    for i in range(row):
        for j in range(column):
            p_v = img[i, j]
            if img[i, j] < t:
                s_c = p_v / t * 125
                t_c = 255 - s_c

            else:
                s_c = (p_v - t) / (255 - t) * 125 + 125
                t_c = 255 - s_c
            temp = i * 1392 + j
            g.add_edge('s', temp, capacity=s_c)
            g.add_edge(temp, 't', capacity=t_c)

    gro = imread('%05d.png' % 200)
    x, y = np.where(gro > 200)
    for i in range(x.shape[0]):
        if img[x[i], y[i]] >= 100:
            temp = x[i] * column + y[i]
            g.add_edge('s', temp, capacity=1000)
    x, y = np.where(img == 0)
    for i in range(x.shape[0]):
        temp = x[i] * column + y[i]
        g.add_edge(temp, 't', capacity=1000)
    return g


def column_components(g, img):
    for i in range(img.shape[0] - 1):
        for j in range(img.shape[1]):
            capacity = lumda * math.exp((-k) * (img[i, j] - img[i + 1, j]) ** 2)
            row_in = img.shape[1] * i
            g.add_edge(j + row_in, img.shape[1] + j + row_in, capacity=capacity)
            g.add_edge(img.shape[1] + j + row_in, j + row_in, capacity=capacity)
    return g


def row_components(g, img):
    for i in range(img.shape[0]):
        for j in range(img.shape[1] - 1):
            capacity = lumda * math.exp((-k) * (img[i, j] - img[i, j + 1]) ** 2)
            row_in = img.shape[1] * i
            g.add_edge(j + row_in, 1 + j + row_in, capacity=capacity)
            g.add_edge(1 + j + row_in, j + row_in, capacity=capacity)
    return g


def create_graph(img, t):
    g = nx.DiGraph()
    N = img.shape[0] * img.shape[1]
    g.add_nodes_from(range(N))
    g = column_components(g, img)
    g = row_components(g, img)
    g.add_nodes_from(['s', 't'])
    g = add_tedges(g, t, img)
    return g


if __name__ == '__main__':
    img = imread("result200.tif")
    # img = np.asarray([[1, 255, 3], [4, 5, 255], [0, 8, 255]])

    # 大津の閾値決定法
    t = threshold_otsu(img)

    row = img.shape[0]
    column = img.shape[1]
    g = create_graph(img, t)
    cut_value, partition = nx.minimum_cut(g, 's', 't')
    s, t = partition
    s = list(s)
    t = list(t)
    print(s)
    result = np.zeros((row, column))
    for i in s:
        if i != 's':
            if i == 0:
                result[0, 0] = 1
            else:
                row_n = i // column
                column_n = i % column
                result[row_n, column_n] = 1
    m = np.zeros((1040, 1392, 3))
    m[:, :, 0] = result * 255
    m = m.astype('uint8')
    print(m.shape)
    img = cv2.imread("result200.tif")
    dst = cv2.addWeighted(img, 0.5, m, 0.5, 0)
    plt.imshow(dst), plt.show()
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1