{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1차시 실습 — 위성 이미지를 숫자로 본다\n",
    "\n",
    "**우송고 위성 AI 8차시 / 1차시**  \n",
    "2026-05-27\n",
    "\n",
    "---\n",
    "\n",
    "## 오늘 할 일\n",
    "\n",
    "1. Colab 에서 Python 셀을 실행한다\n",
    "2. 인터넷에서 위성/우주 이미지를 불러온다\n",
    "3. 이미지를 화면에 띄운다\n",
    "4. 이미지의 크기, 픽셀값, RGB 구조를 확인한다\n",
    "5. RGB 채널을 분리해서 본다\n",
    "\n",
    "## 핵심 메시지\n",
    "\n",
    "> **컴퓨터는 사진을 의미가 아니라 숫자로 본다.**  \n",
    "> 위성 AI 도 결국 이 숫자 배열을 읽는 일이다.\n",
    "\n",
    "## 사용법\n",
    "\n",
    "- 각 코드 셀 왼쪽의 ▶ 버튼을 누르면 실행된다.\n",
    "- 또는 셀을 선택하고 `Shift + Enter`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## STEP 1. 라이브러리 준비\n",
    "\n",
    "이미지 처리에 쓸 도구를 불러온다.\n",
    "\n",
    "- `PIL.Image` — 이미지 열기/저장\n",
    "- `matplotlib.pyplot` — 화면에 그리기\n",
    "- `requests` — 인터넷에서 파일 가져오기\n",
    "- `numpy` — 숫자 배열 처리\n",
    "\n",
    "Colab 에는 모두 미리 설치되어 있다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from PIL import Image\n",
    "import matplotlib.pyplot as plt\n",
    "import requests\n",
    "from io import BytesIO\n",
    "import numpy as np\n",
    "\n",
    "print('준비 완료')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## STEP 2. 위성/우주 이미지 불러오기\n",
    "\n",
    "Apollo 17 에서 찍은 지구 사진(블루 마블)을 불러온다.\n",
    "\n",
    "이미지 출처: NASA / Wikimedia Commons (퍼블릭 도메인)\n",
    "\n",
    "**참고** — 다른 이미지를 쓰고 싶으면 `IMAGE_URL` 만 바꾸면 된다.  \n",
    "백업 URL 도 미리 준비해뒀다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "IMAGE_URL = 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/The_Earth_seen_from_Apollo_17.jpg/1024px-The_Earth_seen_from_Apollo_17.jpg'\n",
    "\n",
    "response = requests.get(IMAGE_URL)\n",
    "img = Image.open(BytesIO(response.content))\n",
    "\n",
    "print('불러오기 성공')\n",
    "print('파일 크기:', len(response.content), 'bytes')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 3. 이미지 화면에 띄우기\n",
    "\n",
    "`matplotlib` 으로 표시한다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(8, 8))\n",
    "plt.imshow(img)\n",
    "plt.axis('off')\n",
    "plt.title('Earth from Apollo 17 (NASA)')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## STEP 4. 이미지 크기와 모드 확인\n",
    "\n",
    "이미지는 가로 × 세로 픽셀로 이루어져 있다.\n",
    "\n",
    "- `img.size` → (가로, 세로)\n",
    "- `img.mode` → 색상 구조. `RGB` 는 빨강/초록/파랑 3채널."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('이미지 크기:', img.size)\n",
    "print('이미지 모드:', img.mode)\n",
    "\n",
    "width, height = img.size\n",
    "print(f'총 픽셀 수: {width * height:,} 개')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 5. 한 픽셀의 값 보기\n",
    "\n",
    "어떤 위치의 픽셀이든 RGB 세 숫자로 표현된다.\n",
    "\n",
    "- (0, 0, 0) → 검정\n",
    "- (255, 255, 255) → 흰색\n",
    "- (255, 0, 0) → 빨강\n",
    "\n",
    "각 채널은 0 ~ 255 의 정수."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 이미지 중앙에서 한 점 찍어보기\n",
    "x = img.size[0] // 2\n",
    "y = img.size[1] // 2\n",
    "\n",
    "pixel = img.getpixel((x, y))\n",
    "print(f'좌표 ({x}, {y}) 의 픽셀:', pixel)\n",
    "print(f'  빨강 = {pixel[0]}')\n",
    "print(f'  초록 = {pixel[1]}')\n",
    "print(f'  파랑 = {pixel[2]}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**도전 1** — 다른 좌표 (예: (100, 100), (500, 700)) 의 픽셀값도 확인해보자. 검정 우주 부분과 푸른 지구 부분의 값이 어떻게 다른가?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 여기에 직접 코드 작성\n",
    "# 예시:\n",
    "# print(img.getpixel((100, 100)))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## STEP 6. 이미지를 숫자 배열로 변환\n",
    "\n",
    "`numpy` 로 변환하면 이미지가 **3차원 숫자 배열**이 된다.\n",
    "\n",
    "- shape = (세로, 가로, 채널)\n",
    "- 채널 = 3 (R, G, B)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "arr = np.array(img)\n",
    "\n",
    "print('배열 shape:', arr.shape)\n",
    "print('배열 자료형:', arr.dtype)\n",
    "print('최솟값:', arr.min())\n",
    "print('최댓값:', arr.max())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 7. RGB 채널 분리\n",
    "\n",
    "3차원 배열의 마지막 축을 잘라 R, G, B 따로 본다.\n",
    "\n",
    "- `arr[:, :, 0]` → 빨강만\n",
    "- `arr[:, :, 1]` → 초록만\n",
    "- `arr[:, :, 2]` → 파랑만\n",
    "\n",
    "지구 사진은 푸른색이 강해서 B 채널이 밝게 나올 것이다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "R = arr[:, :, 0]\n",
    "G = arr[:, :, 1]\n",
    "B = arr[:, :, 2]\n",
    "\n",
    "fig, axes = plt.subplots(1, 3, figsize=(15, 5))\n",
    "\n",
    "axes[0].imshow(R, cmap='Reds')\n",
    "axes[0].set_title('Red channel')\n",
    "axes[0].axis('off')\n",
    "\n",
    "axes[1].imshow(G, cmap='Greens')\n",
    "axes[1].set_title('Green channel')\n",
    "axes[1].axis('off')\n",
    "\n",
    "axes[2].imshow(B, cmap='Blues')\n",
    "axes[2].set_title('Blue channel')\n",
    "axes[2].axis('off')\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 8. 각 채널의 평균값\n",
    "\n",
    "전체 이미지에서 R, G, B 가 평균적으로 얼마인지 본다.  \n",
    "지구 사진이면 B (파랑) 평균이 가장 높을 가능성이 크다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(f'R 평균: {R.mean():.1f}')\n",
    "print(f'G 평균: {G.mean():.1f}')\n",
    "print(f'B 평균: {B.mean():.1f}')\n",
    "\n",
    "# 막대 그래프로 비교\n",
    "plt.figure(figsize=(6, 4))\n",
    "plt.bar(['R', 'G', 'B'], [R.mean(), G.mean(), B.mean()],\n",
    "        color=['#FF3B3B', '#3BFF6E', '#3B8BFF'],\n",
    "        edgecolor='black', linewidth=2)\n",
    "plt.title('Average value per channel')\n",
    "plt.ylim(0, 255)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 도전 과제 (시간 남으면)\n",
    "\n",
    "### 도전 A. 흑백으로 만들기\n",
    "RGB 평균을 내면 흑백 (그레이스케일) 이 된다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gray = arr.mean(axis=2)\n",
    "\n",
    "plt.figure(figsize=(8, 8))\n",
    "plt.imshow(gray, cmap='gray')\n",
    "plt.axis('off')\n",
    "plt.title('Grayscale')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 도전 B. 다른 위성 이미지로 바꿔보기\n",
    "\n",
    "아래 URL 중 하나로 바꿔서 위 코드를 모두 다시 돌려보자.\n",
    "\n",
    "- 야간 지구 (Black Marble): `https://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Black_marble.jpg/1024px-Black_marble.jpg`\n",
    "- 화성: `https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/OSIRIS_Mars_true_color.jpg/800px-OSIRIS_Mars_true_color.jpg`\n",
    "- 목성: `https://upload.wikimedia.org/wikipedia/commons/thumb/2/2b/Jupiter_and_its_shrunken_Great_Red_Spot.jpg/1024px-Jupiter_and_its_shrunken_Great_Red_Spot.jpg`\n",
    "\n",
    "어느 이미지에서 R 평균이 가장 높은가? 왜 그런가?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 여기에 직접 작성\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 도전 C. 한 채널만 강하게 만들기\n",
    "\n",
    "B (파랑) 값을 모두 0 으로 바꾸면 어떻게 보일까?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "arr_no_blue = arr.copy()\n",
    "arr_no_blue[:, :, 2] = 0   # B 채널 = 0\n",
    "\n",
    "plt.figure(figsize=(8, 8))\n",
    "plt.imshow(arr_no_blue)\n",
    "plt.axis('off')\n",
    "plt.title('Blue removed')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 오늘의 정리\n",
    "\n",
    "체크리스트 — 이 셀들이 다 실행됐는가?\n",
    "\n",
    "- [ ] 이미지를 화면에 띄웠다\n",
    "- [ ] 이미지 크기를 출력했다\n",
    "- [ ] 한 픽셀의 RGB 값을 출력했다\n",
    "- [ ] R, G, B 채널을 분리해서 그렸다\n",
    "- [ ] 채널별 평균을 비교했다\n",
    "\n",
    "## 한 줄 정리\n",
    "\n",
    "> **이미지는 숫자 배열이다.**  \n",
    "> 위성 AI 는 이 숫자에서 패턴을 찾는다.\n",
    "\n",
    "## 다음 차시 예고\n",
    "\n",
    "2차시는 이미지가 아니라 **센서 로그 데이터** (고도, 온도, 배터리, 신호) 를 다룬다.  \n",
    "그래프를 그리고, 이상한 값을 찾는다.\n",
    "\n",
    "## 노트북 저장\n",
    "\n",
    "상단 메뉴 → 파일 → Drive 에 저장.  \n",
    "이름: `01_위성이미지_기초_본인이름.ipynb`"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "01_satellite_image_basics.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
