확률 및 랜덤 프로세스 5장 - 정규분포

 

확률 및 랜덤 프로세스 4장 - 연속형 확률분포

지금 하고 있는 프로젝트에서 unity를 이용해서 진행하기로 하였다.
Unity에 있는 가상 카메라로 카메라 정보를 받아 이를 처리하는 방식인데,, 문제는 Unity는 C#을 베이스로 만들어진 툴이기 때문에 다른 언어로 만든 코드를 script로 넣어줄수가 없었다. 그리고 무엇보다도.. 내가 C#을 다뤄본적이 별로 없어서.. python으로 카메라 이미지를 보내줄 수 있는 방법을 찾아보았다.
우선 여러가지 방법을 찾았다. 그렇지만 기왕 ubuntu환경에서 하기로 한거, 한번 rosbridge를 이용해서 해보려고 한다.
rosbridge는 ros와 다른 tool을 이어주는 말 그대로 bridge이다. IoT를 공부하다보면 bridge기기라는게 나오는데, 센서와 엑추에이터 사이를 이어주는 역할을 해준다. 
rosbridge의 경우 나한테 조금은 친숙하다. 마카롱에서 나간 모라이 대회가 똑같이 rosbridge를 통해 ros와 모라이가 통신할 수 있도록 했었다. 이때 디버깅 하면서 조금 공부해 둔게 있기도 하고... 그나마 친숙한 rosbridge를 사용하기로 하였다...
근데..? ROS-Unity통신 관련 자료 왜이리 없냐... 날 너무 힘들게 한 아이.. 그치만 해치웠지.. 후후후...

rosbridge 설치하기

sudo apt-get install ros-noetic-rosbridge-server

rosbridge를 설치해주면 다음은 path를 지정해 주면된다.

source /opt/ros/noetic/setup.bash

그 다음은 로스브릿지 런치파일을 실행해주면 되는데... 이부분은 모라이 할때 단축어 해둔게 있어서 나는 편했다.

roslaunch rosbridge_server rosbridge_websocket.launch

그 다음 내 IP주소를 찾아내야 하는데, 이때 ifconfig를 통해 찾아도 되지만, 나는 그냥 localhost:9090으로 진행하였다.
모라이할 때 실험해보니.. 이게 제일 편하드라고..
자 이렇게 하면 rosbridge의 준비는 끝난다. 이제 unity로 넘어가보자
 

Unity에서 topic publish해주기

우선, Unity에 ROS# 패키지를 install해주어야 한다. Unity내에서 패키지를 찾아서 Assets에 넣는 방법도 있지만.. 뭔가 지금 내가 사용하고 있는 unity버전이 정상적인 버전은 절대 아닌것같아.. git을 이용한 방법으로 소개를 하겠다... (unity깔다가 내 ubuntu 맛탱이 가버렸다.. 나 우분투에서 한글 안쳐짐.. 이상하게 C드라이브에 접근할 수 있어지고.. 개발 환경도 좀 많이 바뀜.. 뭔가를 단단히 잘못한 듯.. ㅠㅠ)
home에 아래 git을 clone 받아주면 된다.

git clone https://github.com/siemens/ros-sharp.git

clone이 다 받아졌다면 사용하고자 하는 프로젝트 Assets에 드래그 해주면 된다. 쉽죠?
이제 ros에 접근할 수 있게 된다. 
여기서 잠깐..!!
Test1/Assets/RosSharp/Scripts/RosBridgeClient/RosCommuncation/에 들어가면 RosConnector.cs파일이 있다.
기본적으로 토픽으로 보낼 모든 센서에 이 RosConnector script를 넣어줘야 하기 때문에, 미리 수정해서 시작하면 편하다.
이 파일을 열어보면, 아래와 같다.

/*
© Siemens AG, 2017-2019
Author: Dr. Martin Bischoff (martin.bischoff@siemens.com)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

<http://www.apache.org/licenses/LICENSE-2.0>.

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

using System;
using System.Threading;
using RosSharp.RosBridgeClient.Protocols;
using UnityEngine;

namespace RosSharp.RosBridgeClient
{
    public class RosConnector : MonoBehaviour
    {
        public int SecondsTimeout = 10;

        public RosSocket RosSocket { get; private set; }
        public RosSocket.SerializerEnum Serializer;
        public Protocol protocol;
        public string RosBridgeServerUrl = "ws://192.168.219.169:9090";

        public ManualResetEvent IsConnected { get; private set; }

        public virtual void Awake()
        {
            IsConnected = new ManualResetEvent(false);
            new Thread(ConnectAndWait).Start();
        }

        protected void ConnectAndWait()
        {
            RosSocket = ConnectToRos(protocol, RosBridgeServerUrl, OnConnected, OnClosed, Serializer);

            if (!IsConnected.WaitOne(SecondsTimeout * 1000))
                Debug.LogWarning("Failed to connect to RosBridge at: " + RosBridgeServerUrl);
        }

        public static RosSocket ConnectToRos(Protocol protocolType, string serverUrl, EventHandler onConnected = null, EventHandler onClosed = null, RosSocket.SerializerEnum serializer = RosSocket.SerializerEnum.Microsoft)
        {
            IProtocol protocol = ProtocolInitializer.GetProtocol(protocolType, serverUrl);
            protocol.OnConnected += onConnected;
            protocol.OnClosed += onClosed;

            return new RosSocket(protocol, serializer);
        }

        private void OnApplicationQuit()
        {
            RosSocket.Close();
        }

        private void OnConnected(object sender, EventArgs e)
        {
            IsConnected.Set();
            Debug.Log("Connected to RosBridge: " + RosBridgeServerUrl);
        }

        private void OnClosed(object sender, EventArgs e)
        {
            IsConnected.Reset();
            Debug.Log("Disconnected from RosBridge: " + RosBridgeServerUrl);
        }
    }
}

여기서 크게 바꿔줘야 할 부분은 없지만.. 나는 로컬 환경에서 진행하기로 하였으니, IP주소를 조금 바꿔주려고 한다.
코드의 32번째 줄의 ip주소를 아래와 같이 바꿔주면, 앞으로 script import할 때마다 주소를 바꿔주는 수고를 덜 수 있다.

public string RosBridgeServerUrl = "ws://localhost:9090";
여기서 하나!!
IP주소를 공부하다보면 정말 많이 헷갈린다.. ifconfig를 치면 내 IP Address를 알 수 있다는건 코딩을 하는 모두가 아는 사실일 것이다. 그런데..! 사실 ifconfig를 출력해보면 정말 많은 주소들이 뜨고, 그중 무엇을 이용해야하는지는 모르는 경우가 많다.
그렇기 때문에 여기서 한 번 정리해주도록 하겠다.

127.0.0.1과 localhost는 같은 의미이다. 그래서 위에서 localhost:9090으로 해주었지만, 이때 127.0.0.1로 해도 같은 곳에 연결된다. 127.0.0.1은 가장 흔히 사용되는 루프백 주소로, 로컬 호스트를 나타낸다. 이 주소를 사용하면 컴퓨터 자체와 통신하는 데 사용할 수 있다.

반면에 192.로 시작하는 주소는 사설 IP 주소 범위 중 하나이며, 일반적으로 내부 네트워크에서 사용된다. 루프백 주소와 사설 IP 주소의 가장 큰 차이는 사용 목적이다. 루프백 주소는 동일한 기기 내에서의 통신을 위한 것이며, 사설 IP 주소는 여러 기기 간의 내부 네트워크 통신을 위한 거다. 

자, 여기서 하나 더! ifconfig를 치면
1: lo:<LOOPBACK~~~~
2: wlp2s0: <BROADCAST~
이런식으로 뜨게 된다.
이렇게 뜰때 우리는 ip주소를 확인할 수 있는데, 하나에 두개가 보여지게 된다. 이때 brd는 broadcasting의 약자로.. inet과 속도 부분에서 큰 차이는 보이지 않는다. 그러나 역시 p-to-p통신보다는 취약하고.. 좀 번거롭다. 그러니 inet 주소를 가져오고 brd주소는 특수한 경우에 사용하면 된다.
여기서 둘!!
이번엔 IP주소에 대해 알아보자.
IP주소에는 크게 두가지 버전이 있다. IPv4(Internet Protocol version 4)와 IPv6(Interent Protocol version 6)
각 버전에는 주소가 할당되는 방식과 주소의 형식에 차이가 있다. 나는 지금 IPv4에 대한 얘기를 하려고 한다.
IPv4는 32비트 주소 공간을 사용해, 보통 4개의 8bit 블록으로 나눠진 10진수로 표현한다.
1. Public Address(공용 주소):
인터넷에서 사용되며, 고유하게 식별된다. 주소 범위는 1.0.0.0에서 223.255.255.255까지이다.

2. Private Address(사설 주소):
내부 네트워크에서 사용된다. 라우터와 NAT(Network Address Translation)을 통해 공용 주소와 통신할 수 있다.
주소 범위에는 세가지가 있다.
10.0.0.0에서 10.255.255.255 - 대규모 기업 등에서 내부 네트워크로 사용하기 적합.
172.16.0.0에서 172.31.255.255 - 중간 규모 기업 혹은 조직에서 내부 네트워크로 사용.
192.168.0.0에서 192.168.255.255 - 가정용 혹은 소규모 비즈니스 네트워크에서 사용.

3. Reserved Address:
특수한 용도로 예약된 주소이다. 대표적으로 0.0.0.0이나, 앞에서 소개한 것처럼 127.0.0.1 혹은 255.255.255.255가 있다.

이것만 알면 당신도 네트워크 할 수 있다..! 
장난이고.. 사실 내가 분명 전공 수업때 배운 내용이지만, 간혹 헷갈리는 일이 있어 한 번 정리해 보았다. 이제 안까먹었으면 좋겠다..
 
자 사담은 여기까지 하고 unity-ros통신을 이어서 진행해 보도록 하겠다.
 
SampleScence에 Emtpy Object를 추가해주고, 이름은 RosConnecter로 설정해준다.
Inspector에 들어가서 Add Component를 눌러주고 ros를 검색하면 사용가능한 Script 목록이 뜬다. 그 중 RosConnector를 선택해주고 저장해주자. 이렇게 하면 이 프로젝트는 ros와 연결이 되게 된다.
여기까지 RosConnector를 만들어주었다.
 
자, 내가 하려고 한건 Ros와 Unity사이 통신을 통해 Ros로 Image를 보내주는 것이다.
Camera를 원하는 곳에 설치하고, 화각(Field of View)까지 설정해주자. 
헷갈림 방지를 위해 카메라 이름 꼭 변경해주자.
그 다음 똑같이 Add Component를 해주면 되는데, 이때 RosConnector말고 Image Publisher의 Script를 선택해주면 자동으로 RosConnector까지 추가가 된다.
이제 topic이름과 어느카메라인지 다시 설정해주면 준비가 얼추 끝나게 된다.
잘 모르겠다면 아래 사진을 참고해볼까요??

오른쪽의 Inspector를 보고 참고해보자.
 
이제 Ros로 넘어와보면, rosbridge 터미널에 아래와 같이 연결되었음을 알리는 것을 볼 수 있다.

2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.348819]: Client connected.  1 clients total.
2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.355182]: Client connected.  2 clients total.
2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.358155]: Client connected.  3 clients total.
2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.361318]: Client connected.  4 clients total.
2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.365238]: Client connected.  5 clients total.

이제 topic 잘 들어오는지 확인 해보자. 여러가지 방법이 있지만, 나는 내가 만들어둔 파이썬 코드를 실행해서 카메라가 잘 들어오고 있는지 확인했다. 

너무 잘 들어온다... 나처럼 미리 만들어둔 코드가 없는데 지금 당장 잘 들어오는지 확인하고 싶다면, rviz나 rqt를 이용하는 방법이 있다.
지금 Image publish의 Frame Id는 Camera로 되어있기 때문에, rviz에서 frame id 바꿔주고 image add 해주면 볼 수 있다.
다른 방법으로는 rqt_graph와 rqt_image이다.

$ rqt_graph
$ rqt_image_view

위의 두가지 명령어로 토픽이 잘 들어오고 있는지 확인할 수 있다.

아이 이뻐라~
 
여기서 다 소개하지는 않았지만, 그 외에도 unity 사용법 익히고.. 내 프로젝트에 맞게 통신환경 설정하고.. 무엇보다도 Unity-Ros통신 자료가 많은 편은 아니라.. 고생 좀 했다..
지금은 이렇게 받아온 이미지 처리를 진행중이다.

현재 진행하고 있는 프로젝트에서 yolo로 object를 인지하고 이에 id값을 부여해 데이터 가공을 진행하고 있다.

Object Tracking

openCV는 몇번 다뤄봤지만, Yolo는 아예 처음이라 데이터 입력값이 어떻게 들어오는지도 몰랐기에.. 유튜브 보면서 공부했고, 내가 알아보기 편하도록 조금 바꿔서 사용하려고 한다.
직전 프레임에서 detection된 object의 center_point를 저장해 뒀다가 그 다음 프레임과 비교했을 때, 거리가 일정 이하이면 같은 id로 판단하는 형식이다.
이를 연속적으로 사용할 수 있도록 하는 것과, 주변에 있는 다른 object와 겹치지 않도록 파라미터 튜닝을 진행하는 것이 관건이다.

#!/usr/bin/env python
#-*-coding:utf-8-*-

import cv2
import numpy as np
import math
from object_detection import ObjectDetection

od = ObjectDetection()
cap = cv2.VideoCapture("blackbox.mp4")

count = 0
center_points_prev = []

tracking_objects = []
track_id = []

while True:
    ret, frame = cap.read()
    count += 1
    if not ret:
        break
    
    # Point current frame
    center_points_cur = []

    # Detect objects on frame
    (class_ids, scores, boxes) = od.detect(frame)
    for box in boxes:
        (x, y, w, h) = box
        cx = int((x + x + w) / 2)
        cy = int((y + y + h) / 2)
        center_points_cur.append((cx, cy))
        # print("FRAME N", count, " ", x, y, w, h)

        # cv2.circle(frame, (cx, cy), 5, (0, 0, 255), -1)
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

    # Only at the beginning we compare previous and current frame
    if count <= 2:
        for pt in center_points_cur:
            for pt2 in center_points_prev:
                distance = math.hypot(pt2[0] - pt[0], pt2[1] - pt[1])
                
                if distance < 20:
                    tracking_objects[track_id] = pt
                    track_id += 1

    else:
        tracking_objects_copy = tracking_objects.copy()
        center_points_cur_frame_copy = center_points_cur.copy()

        for object_id, pt2 in tracking_objects_copy.items():
            object_exists = False
            for pt in center_points_cur_frame_copy:
                distance = math.hypot(pt2[0] - pt[0], pt2[1] - pt[1])

                # Update IDs position
                if distance < 20:
                    tracking_objects[object_id] = pt
                    object_exists = True
                    if pt in center_points_cur:
                        center_points_cur.remove(pt)
                    continue
            
            # Remove IDs lost
            if not object_exists:
                tracking_objects.pop(object_id)

        # Add new IDs found
        for pt in center_points_cur:
            tracking_objects[track_id] = pt
            track_id += 1

    for object_id, pt in tracking_objects.items():
        cv2.circle(frame, pt, 5, (0, 0, 255), -1)
        cv2.putText(frame, str(object_id), (pt[0], pt[1] - 7), 0, 1, (0, 0, 255), -2)


    cv2.imshow("Frame", frame)

    center_points_prev = center_points_cur.copy()
    
    key = cv2.waitKey(1)
    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()

 

나는 여기서 ID유지 뿐만 아니라, 움직이는 방향을 고려해 현재 어느 방향으로 움직이고 있는지 계산하도록 진행할 예정이다.
현재 알고리즘에서는 과거의 center_point는 tracking을 하는데에만 사용된다.
나는 생성된 ID별로 center_point들의 history를 이용해 vector값을 구해보려고 한다.
 
아래는 내가 본 유튜브 링크이다. Object tracking 뿐만 아니라, 카메라를 이용한 다양한 알고리즘을 잘 설명하고 있어, 좋은 것 같다.

https://youtu.be/GgGro5IV-cs?si=3lDZauI8t8Jun7nK

 

이번에 캡스톤디자인에서 yolo를 돌려야 하는데, 문제가 하나 있다..!

내 노트북이 연약한 내장그래픽 사용하는 gram이라는거...

그런 나에게도 yolo를 약하지만 돌릴 수 있는 방법이 있으니.. 바로 구글 colab이다.

구글 드라이브를 연동해서 무료로 gpu를 사용할 수 있다. 물론 사이즈가 큰 학습은 못하지만.. 현재 내 프로젝트는 구현만 되면 되는거 이기도 하고, 높은 정확도를 요구하지는 않아서... 노트북 사기 전까지는 이걸로 하자..

우선 google drive에 들어가서 colab워크스페이스를 열어준다.

colab에 들어왔으면 제일 먼저 해줄 일은, 런타임 유형을 gpu로 바꿔주는 거다.

상단에 런타임 - 런타임 유형변경 에서 gpu로 바꿔주자.

그다음은 내 드라이브와 연동해주어야 한다.

from google.colab import drive
drive.mount('/content/drive')

위 코드를 넣어줘서 연동을 마무리 해주자.

다음은 yolov5 git을 clone받아주자.

cd drive/MyDrive/

디렉토리 이동을 해주고,,

!git clone https://github.com/ultralytics/yolov5

위 명령어를 입력해주면 yolov5가 클론된다.

다음은 데이터셋 zip파일을 구글 드라이브에 올리자. 이때, 그냥 drive에 올리지 말고 clone받은 yolov5디렉토리 안에 올려주도록 하자

cd yolov5/
!unzip -qq "custom_dataset.zip"

위 명령어를 입력해주면, yolov5폴더 내에 custom_dataset이라는 폴더가 새로 생기게 된다. 

Yolo 학습시키기

이제 학습을 위해 yaml파일을 바꿔주어야 한다.

데이터셋은 이미 라벨링 되어있는 공공 데이터셋을 가져왔기 때문에 여기까지만 해줘도 된다.

path: /content/drive/MyDrive/yolov5/custom_dataset
train: train/images
val: valid/images
test: test/images

nc: 5
names: ['Ambulance', 'Bus', 'Car', 'Motorcycle', 'Truck']

이제 학습 돌려주면 된다.

!python train.py --data "data/custom_dataset.yaml" --epochs 100

epoch은 일단 100으로 두고 진행해보자.

열심히 돌아주렴..

Yolo로 detection시키기

여기까지는 학습을 진행하는 방법이었고, 이제 yolo로 detection하는 법을 정리해보려고 한다.

일단, 기본적으로 yolo에서 제일 기본 pt파일과 샘플 이미지를 제공한다.

sample image는 /data/images에 있다. detection해보고 싶은 이미지가 있다면 이 폴더에 jpg형태로 넣어주면 된다.

그 다음 detection 코드를 실행해주면 된다.

!python detect.py --weights yolov5s.pt --img 640 --conf 0.28 --source data/images
# display(Image(filename='runs/detect/exp/im22.jpg', width=600))

아래에 display 부분은 colab에서 돌려서 못쓰는 부분이다. 만약 gpu달린 노트북에서 진행한다면, 아마 detect되면 이미지가 나타날 것이다.

나는 detect가 끝나면 yolov5/runs/detect/ 에 들어가 직접 확인해주었다.

아래는 내가 직접 넣은 이미지를 detection해본거다. 

꽤나 잘 나와서 사실 따로 학습을 시켜야 하나..? 싶지만... 하기는 해야겠지..

딥러닝.. 어렵다.. 

'자율사물캡스톤디자인 > 자료 조사' 카테고리의 다른 글

Unity-ROS 통신하기  (0) 2023.11.22
테슬라 오토파일럿(Autopilot) 기능  (2) 2023.09.26

공간 영역에서 이미지 향상

Introduction

공간 영역의 향상, 주파수 영역에서의 향상

  • 스패클 노이즈 제거
  • 히스토그램 공정
  • 중위 필터링
  • Enhancement :  이미지를 조작하여 결과가 특정 목적에 적합하도록 처리.
  • Techniques of enhancement : 
    • Spatial domain(공간 영역) : 픽셀의 직접적인 조작을 수반.
    • Frequency domain(주파수 영역) : 이미지의 푸리에 변환을 포함.
    • Combination : 공간 및/또는 주파수 영역의 조합
  • Objective : 공간 영역에서 특정 응용 또는 목적을 위해 이미지를 처리
    • X-ray image vs. picture of Mars
    • 공간 영역 vs. 주파수 영역 분석
  • 이미지 향상에 General Theory는 없다.
    • 인간의 인식을 위한 이미지 품질에 대한 시각적 평가는 주관적
    • 다양한 기술의 조합 are not unusual.
    • 더 많은 프로세스가 더 나은 성능을 제공
  • 지정된 위치에서 직접 작동하는 공간 영역 프로세스
    • point(pixel) 기반 프로세스            g(x, y) = T[f(x, y)]
    • area(mask) 기반 프로세스           g(x, y) = f(x, y) * h(x, y)
    • Coefficient vs. size vs. complexity & effect & application
  1. Gray-level (intensity) trasformation
    • g(x, y) = T[f(x, y)]  =>  s = T(r)
    • 올바른 transform curves을 사용하여 가장 간단한 프로세스
    • 대비/엣지 향상, 엣지 샤프닝, 스무딩, 노이즈 제거
    • 위성을 통한 원격 감지, 의료 영상, 복원, 노이즈 제거, 타겟 추적EHistogram processing
    • Point process manipulating its histogram for certain purpose
    • 히스토그램 균등화, 히스토그램 일치, 히스토그램 통계량
  2. Arithmetic or logic operation
    • 단순 향상 응용을 위해 산술 연산이나 논리 연산을 사용하는 포인트 프로세스
    • averaging, subtracting, AND, OR
  3. Spatial filtering
    • area process with 2-D mask
    • smoothing, sharpening (제일 유명)

Gray-level Transformation

공간 영역에서 이니스먼트 방법 4가지.

  • Simplest among all others      g(x, y) = T[f(x, y)]    =>    s = T[r]
  • Image negatives : s = (L - 1) - r
    • enhancing white or gray detail embedded in dark regions
  • Log transformations : s = c * log(1 + r)     {c = constant}
    • expand lower-level values
    • compress higher-level values
  • Power-law transformations : s = c * r^y
    • Display device have intensity-to-voltage response that is power function, exponent varying from r = 1.8~2.5
    • 우리가 사용하고 있는 display unit에는 소자의 밝기나 능력에 따라 표현되는 값이 많이 달라질 수 있다.
    • 전류나 전압값을 이용해 특정 소자값을 특정해주는데, 소자마다 다르기 때문에 사람 눈에 보이는 것도 다 다르게 보인다.
      • r > 1
        => 어두운 부분이 강조 (more detail in bright region) -> 밝은 영역의 결과물을 손쉽게 관찰 가능
      • 0 < r < 1
        => 밝은 부분이 강조 (more detail in dark region) -> r(감마값)을 줄여서 보이지 않던 걸 볼 수 있게 할 수 있다.(어두운 영역을 볼 수 있음)
  • Piecewise-linear transformation
    • Contrast compress/stretching(밝기 감소/증가) - increases dynamic ranae
    • thresholding(특정 영역은 highlight) - highlight region
      • 처리 중인 이미지에서 grey-level의 dynamic range 확장.
      • Intensity level slicing - highlight specific range of gray level
    • bit-plane slicing - analyze relative importance played by each bit
      특정 영상물을 binary 값으로 전환 (bit-plane으로 전환, Gray code로 전환)
      • higher-order bits contain majority of visually significant data
      • Contrast Stretch : 어두운 부분이 전반적으로 밝게 전환.

Histogram Processing

  • 다양한 공간 도메인 프로세스 기반
    • 영상의 밝기 통계를 그래픽으로 표현
    • Compression, segmentation
  • Histogram - 화소의 밝기에 대한 discrete한 함수.
    • normalized histogram
  • Histogram equalization : 어두운 부분과 밝은 부분이 많이 분포할 수 있게 조정. 
    • not flattens but redistributes histogram

 

 

 

 

확률 및 랜덤 프로세스 3장 - 이산형 확률분포

확률 및 랜덤 프로세스 2장 - 확률변수

+ Recent posts