import numpy as np
import matplotlib.pyplot as plt
import cv2
from google.colab import files
from scipy.interpolate import UnivariateSpline
import warnings
# 경고 무시
warnings.filterwarnings('ignore')
def generate_geogebra_code():
print("1. 이미지를 업로드하세요. (흰 배경에 검은 선, 혹은 그 반대)")
uploaded = files.upload()
if not uploaded:
print("파일이 없습니다.")
return
filename = list(uploaded.keys())[0]
file_bytes = np.frombuffer(uploaded[filename], np.uint8)
img = cv2.imdecode(file_bytes, cv2.IMREAD_GRAYSCALE)
# 1. 이미지 전처리 (이진화)
# 배경이 흰색이고 선이 검은색이면 THRESH_BINARY_INV 사용
# 상황에 따라 threshold 값(127)을 조절하세요.
_, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
# 윤곽선 추출
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
print(f"\n>> 분석 시작: 총 {len(contours)}개의 파츠를 분석합니다...")
geogebra_list = [] # 지오지브라 명령어 저장용 리스트
# 시각화용 캔버스 설정
plt.figure(figsize=(10, 10))
plt.axis('equal')
plt.title("Extracted Curves")
count = 0
for contour in contours:
if len(contour) < 10: continue # 너무 짧은 잡음 제거
pts = contour.reshape(-1, 2)
# --- [핵심] 단조 구간(Monotonic Segment) 나누기 ---
# 하나의 x에 하나의 y만 대응되도록 곡선을 자릅니다.
segments = []
current_segment = [pts[0]]
if len(pts) > 1:
# x가 증가하는 방향인지 감소하는 방향인지 초기 설정
direction = 1 if pts[1][0] > pts[0][0] else -1
else:
direction = 0
for i in range(1, len(pts)):
prev_pt = pts[i-1]
curr_pt = pts[i]
dx = curr_pt[0] - prev_pt[0]
if dx == 0: # x변화가 없으면(수직선) 같은 그룹에 추가하고 패스
current_segment.append(curr_pt)
continue
current_dir = 1 if dx > 0 else -1
# 방향이 바뀌면(꺾이면) 여기서 자름
if current_dir != direction:
if len(current_segment) > 5: # 최소 길이 이상일 때만 저장
segments.append(np.array(current_segment))
current_segment = [curr_pt] # 새로운 시작
direction = current_dir
else:
current_segment.append(curr_pt)
# 마지막 남은 조각 추가
if len(current_segment) > 5:
segments.append(np.array(current_segment))
# --- 함수 생성 및 지오지브라 변환 ---
for seg in segments:
x_raw = seg[:, 0]
y_raw = -seg[:, 1] # 이미지 좌표계(y가 아래로 증가)를 수학 좌표계로 반전
# 중복 x값 제거 (평균화)
unique_x = np.unique(x_raw)
clean_y = []
for ux in unique_x:
ys = y_raw[x_raw == ux]
clean_y.append(np.mean(ys))
clean_y = np.array(clean_y)
if len(unique_x) < 4: continue # 점이 너무 적으면 패스
try:
# 3차 다항식 피팅 (Polyfit)
coeffs = np.polyfit(unique_x, clean_y, 3)
# 그래프 그리기 (미리보기용)
x_new = np.linspace(unique_x.min(), unique_x.max(), 50)
p = np.poly1d(coeffs)
y_new = p(x_new)
plt.plot(x_new, y_new, 'r-', linewidth=1)
# --- 지오지브라 문법으로 변환 ---
# Function( <Function>, <Start x-Value>, <End x-Value> )
# 계수 포맷팅: 1.54e-05 -> (1.54*10^(-5)) 형태로 변환해야 안전함
def fmt(n): # 지오지브라용 숫자 포맷터
return f"({n:.5e})".replace("e", "*10^")
func_str = f"{fmt(coeffs[0])}x^3 + {fmt(coeffs[1])}x^2 + {fmt(coeffs[2])}x + {fmt(coeffs[3])}"
# 범위 지정
xmin = unique_x.min()
xmax = unique_x.max()
geo_cmd = f"Function({func_str}, {xmin}, {xmax})"
geogebra_list.append(geo_cmd)
count += 1
except Exception as e:
continue
plt.show() # 미리보기 출력
# --- 결과 파일 생성 및 다운로드 ---
print("\n" + "="*60)
print(f"총 {len(geogebra_list)}개의 함수 조각이 생성되었습니다.")
print("지오지브라용 텍스트 파일을 생성하고 다운로드합니다...")
print("="*60)
# 지오지브라 리스트 형태로 묶기: {Function(...), Function(...)}
full_text = "{" + ", ".join(geogebra_list) + "}"
with open("geogebra_commands.txt", "w") as f:
f.write(full_text)
files.download("geogebra_commands.txt")
print("\n[완료] 다운로드된 'geogebra_commands.txt' 파일을 열어서 내용을 전체 복사 후,")
print("지오지브라 입력창에 한 번에 붙여넣으세요.")
# 함수 실행
generate_geogebra_code()
댓글 0