본문 바로가기

파이썬(PYTHON)

4가지 크기의 입자로 빈 공간을 최대한 채우는 비율

728x90

화면 720 x 720 공간 안에 총 5가지의 반지름을 가진 원의 알깽이는 채울때 빈 공간을 최소로 하는 그 비율을 찾기 위해 본 글과 연구(?)를 실시해 봅니다.

이와 같은 내용이 가지는 의미를 단적으로 설명하다면

모든 재료는 여러가는 재료를 활용한 복합 또는 혼합 재료들로 만들집니다. 이때 성능이나 구조를 좋게하기 위해서는 빈 공간 없이 채우는 것이 중요합니다.

예를 들면, 재료를 구성하여 빈 공간 없이 채우고 싶은데 선택 재료의 종류와 가격이 다를 경우, 그 비율은 아주 중요한 사항이 된다. (방열 시트, 건축 구조물 등 거의 모든 재료에 대해)

따라서 선택된 재료들을 각각 얼마의 비율로 배합 또는 혼합해야만 최대 성능이나 구조적 안정성을 올릴 수 있습니다.

여기에 대해 파이썬을 이용하여 그 비율과 그 한계를 찾아보고자 합니다.

빈 공간이 작을수록 그 성능과 구조는 좋아집니다. 과연 그 비율은 얼마이며 그 비율을 찾기 위한 프로그램은 어떻게 되는지 시도해 보겠습니다.

빈공간 : 21.4625 %

1차 시도 :
#-*- coding:utf-8 -*-
# 특정 공간에 빈 공간없이 최대 격자 채우기

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

w = 720
h = 720
white_color = 255
black_color = 0
radi = 40
img = np.zeros((h, w), dtype = np.uint8)
cou = 0
pp = []
ss = []
rad_10 = 0
rad_20 = 0
rad_30 = 0
rad_40 = 0
while 1:
    x = random.randint((-1)*int(radi/2), h+int(radi/2))
    y = random.randint((-1)*int(radi/2), w+int(radi/2))
    img1 = img.copy()
    a1 = sum(sum((img1 > 127)))
    radi = random.randint(1, 4)*10
   
   
    cv2.circle(img1, (x, y), radi, white_color, -1)
    a2 = sum(sum((img1 > 127)))
    #print(a1, a2)
    if (a2 - a1) > radi*radi*3.1: # 10 : 310, 20 : 1250
        img = img1
        cou += 1
        #print(cou)
        if radi == 10:
            rad_10 += 1
        if radi == 20:
            rad_20 += 1
        if radi == 30:
            rad_30 += 1
        if radi == 40:
            rad_40 += 1
    else:
        img = img

    print(rad_10, rad_20, rad_30, rad_40)
    pp.append(cou)
    ss.append(sum(sum((img == 0)*1))/(720*720))
    cv2.imshow('img', img)
    cv2.waitKey(5)
   
    plt.plot(pp, ss,'.-')
    plt.pause(0.01)
    plt.clf()
   
 

 

2차 시도 :

#-*- coding:utf-8 -*-
# 특정 공간에 빈 공간없이 최대 격자 채우기

 

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

 

w = 720
h = 720
white_color = 255
black_color = 0
radi = 40
img = np.zeros((h, w), dtype = np.uint8)
cou = 0
pp = []
ss = []
rad = [0, 0, 0, 0, 0]
grid = [70, 50, 15, 10, 5] # 입자 직경 5가지에 대해
grid_idx = 0
pos_x = []
while 1:
    radi = grid[grid_idx]
    try_time = 0
    while 1:
        x = random.randint((-1)*int(radi/2), h+int(radi/2))
        y = random.randint((-1)*int(radi/2), w+int(radi/2))
        try_time += 1
        img1 = img.copy()
        a1 = sum(sum((img1 > 127)))
        #radi = grid[random.randint(0, 4)]
        pos_x.insert(x, y)
       
        cv2.circle(img1, (x, y), radi, white_color, -1)

 

        a2 = sum(sum((img1 > 127)))
        #print(a1, a2)
        if (a2 - a1) > radi*radi*3.11: # 10 : 310, 20 : 1250
            img = img1
            cou += 1
            #print(cou)
            for p in range(len(grid)):
                if radi == grid[p]:
                    rad[p] += 1
        else:
            img = img

 

       
        pp.append(cou)
        empty_per = sum(sum((img == 0)*1))/(720*720)
        ss.append(empty_per)

 

        for p in range(len(grid)):
            print(rad[p])
        print(' => ',empty_per)
       
        cv2.imshow('img', img)
        cv2.waitKey(1)
       
        plt.plot(pp[-50:], ss[-50:],'.-')
        plt.pause(0.01)
        plt.clf()
        if len(ss) > 2:
            #if np.mean(ss[-50*(grid_idx+1):]) == empty_per:
            if (np.mean(ss[-50*(grid_idx+1):]) == empty_per) or (try_time > 10**(grid_idx+2)):
                break
    cv2.imwrite('result.png', img)
    if grid_idx < len(grid)-1:
        grid_idx += 1
    else:
        break
   
 

입자 비율 => 10 : 13 : 120 : 115 : 410

결과 빈 공간 비율 : 20.942515432 %

728x90