[PYTHON] Lösen Sie ein 4-Farben-Problem mit Kombinationsoptimierung

Lösen Sie das 4-Farben-Problem

Sie können das 4-Farben-Problem auch mithilfe von [Kombinationsoptimierung] lösen (http://qiita.com/Tsutomu-KKE@github/items/bfbf4c185ed7004b5721). Hier lesen wir das Problem automatisch aus dem Bild. Das Problem kam von Nikori-sama.

Formulierung

Es gibt mehrere Bereiche und angrenzende Bereiche sind in verschiedenen Farben gestrichen.

$ \ mbox {Variablen} $ $ v_ {ij} \ in \ {0, 1 \} ~ \ für alle i, j $ Bereich i Ist die Farbe j? (1)
$ \ mbox {vorbehaltlich} $ $ \ sum_j {v_ {ij}} = 1 ~ \ forall i $ Wählen Sie eine Farbe ( 2)
Benachbarte Bereiche sollten unterschiedliche Farben haben (3)

Löse mit Python

Laden Sie die Bilddatei.

python


import networkx as nx
from urllib import request
from PIL import Image, ImageDraw
from collections import Counter
from itertools import product
from random import seed, shuffle
from pulp import *

#Bilddateien lesen
with request.urlopen('https://dl.dropboxusercontent.com/u/35689878/tmp/4c.png') as fd:
    im = Image.open(fd)

4c.png

  • Extrahieren Sie die repräsentative Zielfarbe als häufige Farbe. Der Bereich ist mit der repräsentativen Farbe gefüllt.
  • Um den Bereich mit der resultierenden Farbe zu malen, werde ich den Bereich einmal mit einer leicht verständlichen Farbe malen (Rot ist 0, Grün ist 1, Blau ist die Bereichsnummer).
  • Setzen Sie zuerst G (grün) von RGB = (0,1,?) Color auf 0.
  • Füllen Sie den repräsentativen Farbbereich mit RGB = (0,1, Seriennummer).
  • Erweitern Sie die Grenzen ein wenig --Wählen Sie einen Punkt nach dem Zufallsprinzip aus. Wenn die Farbe ein Bereich ist und sich ein Pixel daneben in keinem Bereich befindet, machen Sie ihn zu diesem Bereich.

python


#Repräsentative Farbe(Am häufigsten verwendete Farben)Extrakt
cc = sorted([(v, k) for k, v in Counter(im.getdata()).items()])[-1][1]

# RGB=(0,1,?)Beseitigen Sie die Farbe von
for y, x in product(range(im.height), range(im.width)):
    R, G, B = im.getpixel((x, y))[:3]
    if (R, G) == (0, 1):
        im.putpixel(0, 0, B)

#RGB repräsentativer Farbbereich=(0,1,Ordnungsnummer)Füllen mit
n = 0
for y, x in product(range(im.height), range(im.width)):
    if im.getpixel((x, y)) != cc:
        continue
    ImageDraw.floodfill(im, (x, y), (0, 1, n))
    n += 1

#Erweitern Sie die Grenze ein wenig
seed(1)
dd = [(-1, 0), (0, -1), (0, 1), (1, 0)]
for h in range(1):
    l = list(product(range(1, im.height-1), range(1, im.width-1)))
    shuffle(l)
    for y, x in l:
        c = im.getpixel((x, y))
        if c[:2] == (0, 1):
            for i, j in dd:
                if im.getpixel((x+i, y+j))[:2] != (0, 1):
                    im.putpixel((x+i, y+j), c)

Erstellen Sie ein Diagramm mit Bereichen als Punkten und Pixeln zwischen benachbarten Bereichen als Kanten.

python


#Zeigen Sie grafisch, ob sie nebeneinander liegen
g = nx.Graph()
for y, x in product(range(im.height-1), range(im.width-1)):
    c1 = im.getpixel((x, y))
    if c1[:2] != (0, 1):
        continue
    c2 = im.getpixel((x+1, y))
    c3 = im.getpixel((x, y+1))
    if c2[:2] == (0, 1) and c1[2] != c2[2]:
        g.add_edge(c1[2], c2[2])
    if c3[:2] == (0, 1) and c1[2] != c3[2]:
        g.add_edge(c1[2], c3[2])

Formulieren und lösen.

python


#Lösen Sie das 4-Farben-Problem
r4 = range(4)
m = LpProblem() #Mathematisches Modell
#Ob Bereich i Farbe j gemacht werden soll(1)
v = [[LpVariable('v%d_%d'%(i, j), cat=LpBinary) for j in r4] for i in g.nodes()]
for i in g.nodes():
    m += lpSum(v[i]) == 1 # (2)
for i, j in g.edges():
    for k in r4:
        m += v[i][k] + v[j][k] <= 1 # (3)
m.solve()
co = [(97, 132, 219), (228, 128, 109), (255, 241, 164), (121, 201, 164)] #4 Farben
rr = [int(value(lpDot(r4, i))) for i in v] #Ergebnis
for y, x in product(range(im.height-1), range(im.width-1)):
    c = im.getpixel((x, y))
    if c[:2] == (0, 1): #Wenn es sich um einen Bereich handelt, malen Sie mit dem Ergebnis
        ImageDraw.floodfill(im, (x, y), co[rr[c[2]]])
im.save('result.png')

result.png

Als ich es tatsächlich versuchte, war es in Ordnung.

cong.png

das ist alles

Recommended Posts