<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>real_jun9u.log</title>
        <link>https://velog.io/</link>
        <description>생각</description>
        <lastBuildDate>Wed, 16 Mar 2022 05:47:50 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>real_jun9u.log</title>
            <url>https://images.velog.io/images/real_jun9u/profile/22642e9e-6212-421a-82ab-4c33e69d3a7a/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. real_jun9u.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/real_jun9u" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Data Mining] 3. Data Exploration]]></title>
            <link>https://velog.io/@real_jun9u/Data-Mining-3.-Data-Exploration</link>
            <guid>https://velog.io/@real_jun9u/Data-Mining-3.-Data-Exploration</guid>
            <pubDate>Wed, 16 Mar 2022 05:47:50 GMT</pubDate>
            <description><![CDATA[<h3 id="data-exploration-and-its-objectives">Data Exploration and its Objectives</h3>
<p>주어진 데이터 셋의 특성, 관계를 파악하는 것은 문제 해결에 중요한 부분이다.
Data Exploration의 목적은 데이터의 특징 파악인데 분포, 이상값, 특성의 수, 특성 간의 관계 유무 등을 파악한다.</p>
<h3 id="data-sets-and-attributes">Data Sets and Attributes</h3>
<p>테이블 형태의 데이터 셋을 구조화된 데이터 셋(Structured Data Set)이라고 한다.
<img src="https://images.velog.io/images/real_jun9u/post/24ba9873-9154-4718-8277-61cd1e545a6a/image.png" alt=""></p>
<ul>
<li>Data Object : </li>
<li>Attribute : 각 Data Object마다 가지고 있는 속성.</li>
<li>attribute의 수가 크면 Data의 Dimensionality가 크다고하고, Object가 많으면 Sample의 수가 크다고 말한다.</li>
</ul>
<h3 id="types-of-data-attributes">Types of Data Attributes</h3>
<ul>
<li>Nominal/Ordinal/Integer/Ratio attributes</li>
<li>Discrete/Continuous attributes</li>
<li>Symmetric/Asymmetric attributes</li>
</ul>
<h4 id="nominalordinalintegerratio-attributes">Nominal/Ordinal/Integer/Ratio attributes</h4>
<p>attributes를 구분하는 방법은 4가지 연산 중 어떤 것을 적용해야 유용한가로 나뉜다.</p>
<ol>
<li>Distictness : $=,\not=$</li>
<li>Order : $\lt,\gt$</li>
<li>Addition : $+,-$</li>
<li>Multiplication: $\times,\div$</li>
</ol>
<ul>
<li>Nominal : 1. ex)ID, 눈 색깔, 우편 번호</li>
<li>Ordinal : 1,2 ex) 점수, 키</li>
<li>Interval : 1,2,3 ex) 날짜, 온도</li>
<li>Ratio : 1,2,3,4 ex) 길이, 나이, 개수
Nominal과 Ordinal은 일반적으로 카테고리 값을 가지는 속성이다. 카테고리 간의 순서를 매길 수 있으면 Ordinal, 매길 수 없으면 Nominal 속성으로 볼 수 있다. Interval과 Ratio는 보통 Numeric 값을 가지는 속성이다. Interval 속성과 Ratio 속성의 차이는 Ratio 속성에서 0은 존재하지 않음을 뜻하지만 Interval 속성에서는 그렇지 않다. 예를들어 길이가 0인 것이나 개수가 0이면 없는 것이다.</li>
</ul>
<h4 id="discretecontinuous-attributes">Discrete/Continuous attributes</h4>
<p>말 그대로 유한한 값을 가지면 Discrete, 연속적인 값을 가지면 Continuous이다.</p>
<h4 id="symmetricasymmetric-attributes">Symmetric/Asymmetric attributes</h4>
<ul>
<li>Asymmetric attributes : 0이 아닌 값만 중요하게 고려되는 속성 ex) 학생들이 공통적으로 수강하는 과목(학생들이 같이 듣지 않는 과목에 대해서는 중요하게 보지 않음)</li>
<li>Symmetric attributes : 0인 값도 0이 아닌 값과 같이 중요하게 여기는 속성. Asymmetric과 반대.</li>
</ul>
<h3 id="types-of-data-exploration">Types of Data Exploration</h3>
<ul>
<li>Descriptive statistics : 속성의 평균, 범위, 편차 등의 정보를 파악</li>
<li>Visualization techniques : 데이터를 시각화해 상관관계, 분포를 파악</li>
</ul>
<h4 id="descriptive-statistics--univariate-exploration">Descriptive statistics : Univariate Exploration</h4>
<p>하나의 속성에 대해 데이터 분석. 해당 속성의 평균, 중앙값, 최빈값, 범위, 표준편차 등을 조사한다.</p>
<ul>
<li><p>mean : 산술적인 평균. 이상치에 민감</p>
</li>
<li><p>median : 데이터를 정렬하였을 때의 중앙값. 이상치에 민감하지 않다</p>
</li>
<li><p>mode : 가장 많이 나타나는 값.
위 세개의 속성을 알아보면 데이터의 분포를 추정할 수 있다.
<img src="https://images.velog.io/images/real_jun9u/post/c1968722-1903-4b8c-b7a4-c3eb09b20f9e/image.png" alt=""></p>
</li>
<li><p>Range : 데이터의 최소값에서 최대값까지의 범위.</p>
</li>
<li><p>Standard deviation : 평균으로부터 데이터들이 얼마나 떨어져 분포하는 지를 나타내는 지표. 표준화를 하므로 Range보다 분포를 파악하기에 좋다.</p>
</li>
<li><p>특정 클래스의 속성 분석(iris setosa species)
<img src="https://images.velog.io/images/real_jun9u/post/c572e965-b917-401a-804f-22c5e5c38740/image.png" alt=""></p>
</li>
<li><p>전체 클래스의 속성 분석
<img src="https://images.velog.io/images/real_jun9u/post/87ddd8cc-d2a3-4a00-91f7-8c890c366efa/image.png" alt=""></p>
</li>
<li><p>해석 : 특정 클래스의 속성에서는 표준 편차가 작았던 Petal Length 속성이 전체 데이터에 대해서는 편차가 크다. 이는 </p>
</li>
</ul>
<h4 id="descriptive-statistics--multivariate-exploration">Descriptive statistics : Multivariate Exploration</h4>
<p>동시에 하나 이상의 속성에 관해서 분석. 속성간의 관계를 파악하는 것이 목적이다.</p>
<ul>
<li>Correlation : Pearson correlation coefficient(r)로 측정하는데, 피어슨 상관 계수는 속성 간의 선형 관계를 표현한다.
$-1 \leq r \leq 1$의 범위를 가지며 r의 절댓값이 1에 가까울수록 두 속성이 선형적으로 상관성이 크고, 0에 가까우면 서로 상관성이 없다고 해석할 수 있다.</li>
<li>한계 : 속성들이 평균, 분산, 상관계수가 모두 같아도 분포가 매우 다를 수 있다. 상관계수 r은 선형 관계만 보일 수 있고 비선형적인 관계에 대해서는 나타내지 못한다.
<img src="https://images.velog.io/images/real_jun9u/post/d21b549b-6ab3-4db3-a2f4-db7526cac5da/image.png" alt=""></li>
</ul>
<h3 id="data-visualization">Data Visualization</h3>
<p>데이터를 그래프와 같이 시각화하여 분석하는 방법</p>
<ul>
<li>Univariate visualization: 하나의 속성에 대해 조사</li>
<li>Multi-variate visualization: 동시에 여러개의 속성에 대해 조사</li>
<li>Visualizing high-dimensional data in parallel axes : 많은 속성에 대해 조사</li>
</ul>
<h4 id="univariate-visualization---histogram">Univariate Visualization - Histogram</h4>
<p>단일 속성의 데이터 분포를 대략적으로 파악하기 위한 도구
Numeric Data가 있을 때 bin value에 따라 막대 개수를 다르게 하여 분포를 대략적으로 혹은 자세하게 볼 수 있다.
아래처럼 히스토그램을 클래스 별로 구분하여 보았을 때 유용하게 정보를 얻을 수도 있다.
<img src="https://images.velog.io/images/real_jun9u/post/53fe7f05-a4aa-4fcc-9969-66e3e80850ff/image.png" alt=""></p>
<h4 id="univariate-visualization---box-plot">Univariate Visualization - Box plot</h4>
<p>속성의 주요 정보인 중앙값, 사분위수, 이상값 등을 파악하기 위한 도구
<img src="https://images.velog.io/images/real_jun9u/post/355619fe-1482-44ba-b904-87f3886e0541/image.png" alt="">
평균, 표준 편차를 보여주는 경우도 있고 여러 속성에 대해 나타내어 속성들의 정보를 빠르게 파악하거나 동일 속성을 클래스 별로 나누어 그려서 분포 특성을 볼 수 있다.
<img src="https://images.velog.io/images/real_jun9u/post/54db827f-1580-4568-bf58-3d636e43b8a6/image.png" alt=""></p>
<h4 id="univariate-visualization---distribution-plot">Univariate Visualization - Distribution plot</h4>
<p>Continuous Numeric 값을 가지는 속성에 대해 분석하는 도구
히스토그램과 비슷한 시각을 제공하지만 연속된 값에 대한 분포를 보여준다.
<img src="https://images.velog.io/images/real_jun9u/post/04b5abd5-898e-4d7f-95bb-38c762dd7622/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Data Mining] 2. Data Mining Process]]></title>
            <link>https://velog.io/@real_jun9u/Data-Mining-2.-Data-Mining-Process</link>
            <guid>https://velog.io/@real_jun9u/Data-Mining-2.-Data-Mining-Process</guid>
            <pubDate>Mon, 14 Mar 2022 07:17:12 GMT</pubDate>
            <description><![CDATA[<p>데이터 마이닝의 단계와 단계별로 고려해야하는 점들을 잘 알아야한다.</p>
<h2 id="generic-steps">Generic Steps</h2>
<p><img src="https://images.velog.io/images/real_jun9u/post/193a46cc-7070-46e1-99e0-804488c155e6/image.png" alt=""></p>
<ol>
<li>Prior Knowledge - 현재 문제, 분야에 대한 사전 지식과 생성되는 데이터에 대한 이해. 이를 통해 어떤 데이터를 사용할 지를 결정할 수 있다.</li>
<li>Preparation - Prior Knowledge에서 결정된 데이터를 Mining할 때 더 효율적이고 원하는 포맷으로 전처리한다.</li>
<li>Modeling - 데이터가 준비되면 학습할 데이터에 대해 적용할 모델, 알고리즘을 설계하고 학습시킨다. 학습된 모델에 대해 Test를 통해 성능을 측정하고 개선시키는 과정이 반복될 수 있다.</li>
</ol>
<h3 id="step-1-understanding-businessdata">Step 1. Understanding Business/Data</h3>
<ul>
<li>Prior knowledge in the objective of business<ul>
<li>해결해야하는 문제가 무엇인지 (Classification, Regression, etc.)</li>
</ul>
</li>
<li>Prior knowledge in the subject area<ul>
<li>문제와 관련된 일, 과정이 어떻게 이루어 지는지</li>
</ul>
</li>
<li>Prior knowledge in the data<ul>
<li>데이터가 저장되고 변환되고 사용되는 방식</li>
<li>문제와 관련된 데이터,특성이 어떤 것이 있는지</li>
<li>데이터들 중 문제 해결을 위해 어떤 데이터가 필요한지</li>
</ul>
</li>
<li>Terminology<ul>
<li>Data Set - Structured Data의 집합, 모음</li>
<li>Data Point(Instance,Sample) - Data Set에서 each row</li>
</ul>
</li>
</ul>
<h3 id="step-2-data-preparation">Step 2. Data Preparation</h3>
<ul>
<li>가장 시간이 많이 들고 중요한 과정</li>
<li>Data Mining Algorithms에서 필요한 만큼 잘 만들어진 데이터는 거의 없다. - 구조화되지 않거나 틀리거나 빠진 데이터들이 존재한다.</li>
<li>Data Preparation에서 할 일<ul>
<li>Data exploration</li>
<li>Handling data quality and missing values</li>
<li>Data types and conversion, transformation,</li>
<li>Outliers, feature selection, data sampling<h4 id="data-exploration">Data Exploration</h4>
데이터를 어떻게 처리할 지 결정하기 위해 데이터를 조사, 탐색. 문제 해결 방향에 대한 방향을 잡아가는 과정
<img src="https://images.velog.io/images/real_jun9u/post/e0aa9442-9154-48de-92fa-529d72a19660/image.png" alt=""><h4 id="handling-data-quality">Handling Data Quality</h4>
</li>
</ul>
</li>
<li>Data Clening을 통해 데이터의 품질을 높인다<ul>
<li>중복된 데이터 제거. 중복에 대해 편향되어 성능을 낮출 수 있다.</li>
<li>이상치(outlier) 데이터 제거. 예측하고자 트렌드, 경향에 대해 이상치를 반영하면 모델의 성능을 낮출 수 있다.</li>
<li>빠진 데이터(missing value)에 대한 처리</li>
<li>데이터 값에 대한 표준화</li>
</ul>
</li>
</ul>
<h4 id="handling-missing-value">Handling Missing Value</h4>
<ul>
<li>데이터 셋에서 특성 값이 빠진 이유를 이해하고 이에 대해 처리해야한다.<ul>
<li>방법1. missing value에 데이터 셋의 해당 특성에서 도출될 수 있는 값을 넣는다. ex) mean, min, max, median 중 어떤 것을 사용할 지는 상황에 따라 선택</li>
<li>방법2. missing value가 포함되는 record(instance)를 제거한다. 이 때 데이터 셋의 사이즈가 적어져 데이터가 많지 않을 때는 좋지 않을 수 있다.</li>
</ul>
</li>
</ul>
<h4 id="data-types-and-conversion">Data Types and Conversion</h4>
<ul>
<li>목적에 따라 특성 값의 타입을 변환해야 하는 경우가 있다.<ul>
<li>Categorical, Numeric Value, Integer Numeric, etc..</li>
<li>Regression 문제에서는 Categorical 값을 numeric value로 변환해야 성능이 개선된다.</li>
</ul>
</li>
</ul>
<h4 id="transformation">Transformation</h4>
<ul>
<li>어떤 특성이 다른 특성들과의 값의 범위보다 많이 클 경우에 결과에 Dominate 할 수 있다. 이 경우 normalize를 통해 값의 범위를 동일하게 만들어야 한다.</li>
</ul>
<ol>
<li>[0,1]의 범위로 정규화
<img src="https://images.velog.io/images/real_jun9u/post/1654c0a3-494b-48b5-8fbd-25e98739e8bb/image.png" alt=""></li>
<li>표준 점수로 변환
<img src="https://images.velog.io/images/real_jun9u/post/1aef7401-1008-43df-96a1-e878f549e5ec/image.png" alt=""></li>
</ol>
<h4 id="outlier">Outlier</h4>
<p>이상치(Outlier)가 예측하거나 해결하려는 경향에 안좋은 영향을 줄 수 있다.</p>
<h4 id="feature-selection">Feature Selection</h4>
<p>주어진 데이터 셋에서 어떤 Feature를 학습을 위해 사용할 지 선택하는 과정.</p>
<ul>
<li>Curse of Dimensionality - Feature의 수가 커질수록 모델이 Complex해지고 성능이 하락할 수 있다. Dimensionality가 높을수록 Data는 Sparse 해진다.</li>
<li>모든 Feature가 문제 해결에 중요하지 않을 수 있고, 상관관계가 있는 데이터도 존재한다. 이러한 Feature를 줄이는 것이 성능이 더 향상된다.</li>
</ul>
<h4 id="data-sampling">Data Sampling</h4>
<p>데이터 셋에서 sample(instance)을 고르는 과정.</p>
<ol>
<li>데이터가 많은 경우 학습에 시간이 많이 소요되므로 가지고 있는 데이터 셋의 특성을 파악하기 위해 사용</li>
<li>학습 데이터와 테스트 데이터를 나누기 위해 사용</li>
</ol>
<h3 id="step-3-modeling">Step 3. Modeling</h3>
<p>주어진 데이터 셋 사이의 관계를 잘 표현하는 모델을 설계하고 학습시키는 단계. 풀려고 하는 문제에 따라 모델의 구조가 달라진다.
<img src="https://images.velog.io/images/real_jun9u/post/d1efbe4f-f0b5-47c4-bad6-5995f26f087f/image.png" alt=""></p>
<ul>
<li>학습 데이터 셋과 테스트 데이터 셋의 크기 비율은 상황에 따라 적절하게 구성해야한다.</li>
</ul>
<h4 id="algorithm-or-modeling-techniques">Algorithm or Modeling Techniques</h4>
<h3 id="step-4-application-or-deployment">STEP 4. Application or Deployment</h3>
<h3 id="step-5-knowledge">STEP 5. Knowledge</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Artificial Intelligence] 1. Introduction]]></title>
            <link>https://velog.io/@real_jun9u/Artificial-Intelligence-1.-Introduction</link>
            <guid>https://velog.io/@real_jun9u/Artificial-Intelligence-1.-Introduction</guid>
            <pubDate>Tue, 08 Mar 2022 05:04:21 GMT</pubDate>
            <description><![CDATA[<h2 id="1장-인간-지능을-흉내내는-인공지능">1장. 인간 지능을 흉내내는 인공지능</h2>
<h3 id="11-지능이란">1.1 지능이란?</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm 1] 1. Introduction]]></title>
            <link>https://velog.io/@real_jun9u/Algorithm-1-1.-Introduction</link>
            <guid>https://velog.io/@real_jun9u/Algorithm-1-1.-Introduction</guid>
            <pubDate>Tue, 08 Mar 2022 01:21:15 GMT</pubDate>
            <description><![CDATA[<p>1</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Data Mining] 1. Introduction]]></title>
            <link>https://velog.io/@real_jun9u/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%A7%88%EC%9D%B4%EB%8B%9D-1.-Introduction</link>
            <guid>https://velog.io/@real_jun9u/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%A7%88%EC%9D%B4%EB%8B%9D-1.-Introduction</guid>
            <pubDate>Mon, 07 Mar 2022 06:03:51 GMT</pubDate>
            <description><![CDATA[<h3 id="what-is-data-mining">What is Data Mining?</h3>
<p>Extraction of Interesting (Non-Trivial, Implicit, Previously Unkown and Potentially Useful) Patterns or Knowledge from large amount of data. it is also referred to as Knowledge Discovery from Data(KDD), Knowledge Extraction, Data/Pattern analysis.</p>
<h3 id="data-mining-tasks">Data Mining Tasks</h3>
<ul>
<li>Classification</li>
<li>Regression</li>
<li>Association Analysis</li>
<li>Clustering</li>
<li>Anomaly Detection</li>
<li>Time Series Analysis</li>
<li>Text Mining</li>
</ul>
<h3 id="category-of-data-mining-tasks">Category of Data Mining Tasks</h3>
<h4 id="predictive-tasks">Predictive tasks</h4>
<ul>
<li>To predict unknown or future value of particular attribute based on the values of other attributes.<blockquote>
<p>Target Variable vs Explanatory Variables
Cost Prediction, Risk Prediction
ex) Classification, Regression, Anomaly Detection</p>
</blockquote>
</li>
</ul>
<h5 id="predictive-tasks---bulding-representative-models">Predictive Tasks :  Bulding Representative Models</h5>
<ul>
<li>Data Mining is the process of building the representative model that fits the observation data with two purposes</li>
<li>Model : the representation of a relationship between variables in a dataset.</li>
</ul>
<ol>
<li>Model predicts the output based on the input variables</li>
<li>Model can be used to understand the relationship betseen the output variable and all the input variables</li>
</ol>
<h4 id="descriptive-tasks">Descriptive tasks</h4>
<ul>
<li>To find human-interpretable Patterns that summarize the underlying relationships in the data<blockquote>
<p>Correlations, Trends, Clusters, Anomalies
ex) Clustering, Association Analysis</p>
</blockquote>
</li>
</ul>
<h5 id="descriptive-task-summarizing-past-events">Descriptive Task: Summarizing Past Events</h5>
<ul>
<li>Data Mining is the process of summarizing the observational data with two purposes</li>
</ul>
<ol>
<li>To provide new, non-trivial information about what happened</li>
<li>To find humaninterpretable patterns
ex) Identifying web pages thar are accesed together, Identifying and describing groups of customers with common buying behavior</li>
</ol>
<h3 id="learning-models-for-dm-tasks">Learning Models for DM Tasks</h3>
<h4 id="supervised-learning">Supervised learning</h4>
<ul>
<li>To infer a function or relationship based on Labeled traning data</li>
<li>To predict the value of output variable based on input variables. ex) Classification, Regression</li>
</ul>
<h4 id="unsupervised-learning">Unsupervised learning</h4>
<ul>
<li>To uncover hidden patterns in Unlabeled data. There are no output variable to predict</li>
<li>To find patterns based on the relationship between instances. ex) Clustering, Association analysis</li>
</ul>
<h3 id="classification---applications">Classification - Applications</h3>
<ol>
<li>Direct Marketing</li>
</ol>
<ul>
<li>Goal : Reduse cost of mailing by targeting a set of consumers likely to buy a product</li>
<li>Approach<blockquote>
<ul>
<li>Use the data for a similar product introduced before</li>
<li>We know which customer decied to buy and which dicided otherwise. This buy or don&#39;t buy decision forms the class attribute(target)</li>
<li>Collect various demographic, lifestyle, and company-interaction related information about all such customers</li>
<li>Use Information as input attributes to learn a classifier model</li>
</ul>
</blockquote>
</li>
</ul>
<ol start="2">
<li>Fraud Detection</li>
</ol>
<ul>
<li>Goal: Predict fraudulent cases in credit card transactions</li>
<li>Approach<blockquote>
<ul>
<li>Use credit card transactions and the information on its account-holder
as attributes</li>
<li>When does a customer buy, what does he buy, how often he pays on time,
etc</li>
<li>Label past transactions as fraud or fair transactions. This forms the class attribute</li>
<li>Learn a model for the class of the transactions</li>
<li>Use this model to detect fraud by observing credit card transactions on
an account.</li>
</ul>
</blockquote>
</li>
</ul>
<p>or Customer Attrition/Churn, Sky Survey Cataloging, Classifying galaxies etc..</p>
<h3 id="regression">Regression</h3>
<h4 id="definition">Definition</h4>
<ul>
<li>To predict a value of a given continuous valued attribute based on the values of other attributes, assuming a linear or nonlinear model of dependency</li>
<li>Greatly studied in statistics, neural network fields.</li>
<li>Examples<blockquote>
<ol>
<li>Predicting sales amounts of new product based on advertising expenditure</li>
<li>Predicting wind velocities as a function of temperature, humidity, air pressure, etc.</li>
<li>Time series prediction of stock market indices.</li>
</ol>
</blockquote>
</li>
</ul>
<h3 id="clustering">Clustering</h3>
<h4 id="definition-1">Definition</h4>
<ul>
<li><p>Given a set of data objects, each having a set of attributes, and a similarity measure among them, find clusters such that 1. data objects in one cluster should be more similar to one another 2. data objects in seperate clusters are less similar to one another</p>
</li>
<li><p>Similarith measures:</p>
</li>
<li><p>Euclidean distance if attirutes are continuous</p>
</li>
<li><p>Other problem-specific measures.</p>
</li>
</ul>
<h4 id="applications">Applications</h4>
<ol>
<li>Market Segmentation</li>
</ol>
<ul>
<li>Goal: To subdivide a market into distinct subsets of customers where any subset may conceivably be selected as a market target to be reached with a distinct marketing mix.</li>
<li>Approach<blockquote>
<ul>
<li>Collect different attributes of customers based on their geographical and lifestyle related information.</li>
<li>Find clusters of similar customers.</li>
<li>Measure the clustering quality by observing buying patterns of customers in same cluster vs. those from different clusters. </li>
</ul>
</blockquote>
</li>
</ul>
<ol start="2">
<li>Document Clustering</li>
</ol>
<ul>
<li>Goal: To find groups of documents that are similar to each
other based on the important terms appearing in them.</li>
<li>Approach:<blockquote>
<ul>
<li>To identify frequently occurring terms in each document.</li>
<li>Form a similarity measure basedon the frequencies of different terms.</li>
<li>Use it to cluster.</li>
</ul>
</blockquote>
</li>
</ul>
<p>etc.</p>
<ul>
<li>Custom profiling for targeted marketing</li>
<li>Group related documents for browsing</li>
<li>Group genes and proteins that have similar functionality</li>
<li>Group stocks with similar price fluctuations</li>
<li>Reduce the size of large data sets</li>
</ul>
<h3 id="association-analysis">Association Analysis</h3>
<h4 id="definition-2">Definition</h4>
<ul>
<li>Given a set of recoreds each of which contain some number of items sfrom a given collection.</li>
<li>To produce dependency rules which will predict occurrence of an item based on occurremces of other items.<h4 id="applications-1">Applications</h4>
</li>
<li>Market-basket analysis : Rules are used for sales promotion, shelf management, and inventory management</li>
<li>Telecommunication alarm diagnosis : Rules are used to find combination of alarms that occur together frequently in the same time period</li>
<li>Medical Informatics : Rules are used to find combination of patient symptoms and test results associated with certain diseases</li>
</ul>
<h3 id="anomaly-detection">Anomaly Detection</h3>
<ul>
<li>Detect significant deviations from normal behavior</li>
<li>Examples : Credit Card Fraud Detection, Network Intrusion Detection</li>
</ul>
<h3 id="time-series-forecasting">Time Series Forecasting</h3>
<ul>
<li>Time series adds an explicit order dependence between observations</li>
<li>Forecasting is to use historical data to predict future observations.</li>
</ul>
<h3 id="text-mining">Text Mining</h3>
<ul>
<li>A type of data mining where the input data is text</li>
<li>Text can be in the form of documents, messages, emails, etc.</li>
<li>Text files are converted into document vectors(Structured data), then standard DM tasks can be applied</li>
</ul>
<h3 id="challenges-of-data-mining">Challenges of Data Mining</h3>
<ul>
<li>Scalability : big datas</li>
<li>High Dimensionality : many meatures</li>
<li>Heterogeneous and Complex Data : many type of data</li>
<li>Data Ownership and Distribution</li>
<li>Non-traditional Analysis</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[영상처리 기초] 2. Homogeneous Coordinates]]></title>
            <link>https://velog.io/@real_jun9u/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-%EA%B8%B0%EC%B4%88-2.-Homogeneous-Coordinates</link>
            <guid>https://velog.io/@real_jun9u/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-%EA%B8%B0%EC%B4%88-2.-Homogeneous-Coordinates</guid>
            <pubDate>Sun, 30 Jan 2022 14:00:10 GMT</pubDate>
            <description><![CDATA[<h2 id="homogeneous-coordinates">Homogeneous Coordinates</h2>
<p>Homogeneous 좌표는 (x,y)를 (wx,wy,w)로 표현하는 것으로 스케일은 무시되고 x,y에 대한 무한히 많은 표현이 존재하게 된다. 3차원에 경우에는 (x,y,z)가 (wx,wy,wz,w)로 표현된다.
Homogeneous 좌표 (x,y,w)에서 원래의 좌표로 구할 때는 (x/w,y/w,1)로 구할 수 있는데, 끝자리가 1이 되도록 스케일링하고 1을 제거하면 된다.
Homogeneous 좌표는 컴퓨터 그래픽스, 비전쪽에서 활용되는데, Homogeneous 좌표계를 사용하면 Affine 변환, Perspective 변환을 하나의 단일 행렬로 표현할 수 있기 때문이다. 점과 벡터는 변환 시 다른 연산을 수행하였는데, Homogeneous 좌표계에서는 동일하게 행렬 연산으로 변환할 수 있게된다.
원래의 좌표계는 Euclidean Geometry의 Cartesian Coordinate System을 사용한다. 유클리디언 기하학이 아닌 Projective Geometry가 있는데, 여기서 사용하는 좌표계가 Homogeneous 좌표계로, Projective 좌표라고도 한다.
카메라 영상은 3차원 공간의 점을 이미지 평면에 Projection한 것이다. 카메라 초점과 투영된 점을 잇는 선을 그으면 이 선 상의 모든 3D 점은 모두 동일한 점으로 투영된다. 이미지 평면상의 점에 대한 Homogeneous 좌표는 이 점에 투영되는 모든 점들을 표현할 수 있게 된다. 또 다른 장점은 무한대의 점을 유한 좌표로 표현할 수 있는 것인데, (x,y)방향의 무한한 점을 (x,y,0)으로 표현할 수 있는 것이다.</p>
<h2 id="projective-geometry">Projective Geometry</h2>
<p>사영 기하학(Projective Geometry)는 투영 변환(Projection Tranformation)에 대한 불변인 기하학적인 특성을 연구하는 것으로 나와있다. 사영 기하학은 Projection을 다루는 기하학으로 1차원 사영 기하학은 2차원 평면에서 1차원 선으로 투영하는 관계, 2차원 사영 기하학은 3차원 공간에서 2차원 평면으로 투영하는 관계를 설명하는 것이다.
사영 기하학에서는 길이, 각도, 평행성이 보존되지 않는다. 이는 3D 공간이 투영된 영상을 생각해보면 이해할 수 있다. 사영 기하학에서는 Type이 보존되는데, 직선은 직선으로 곡선은 곡선으로 투영된다. 포함관계 또한 보존이 된다.</p>
<h2 id="점-선-그리고-외적">점, 선 그리고 외적</h2>
<p>직선의 방정식을 Homogeneous 형태로 표현하면 아래처럼 된다.
$ax+by+c=0\ax+by+cw=0$
이 때 $u=\begin{bmatrix}a&amp;b&amp;c\end{bmatrix}^T, p = \begin{bmatrix}x&amp;y&amp;w\end{bmatrix}^T$ 로 두면 $u^Tp=0$ 또는 $p^Tu=0$이 된다. 점 p가 직선 u 위에 존재할 조건은 $u^Tp=0$이 되는 것이다.
여기서 발생하는 성질이 있는데, 두 직선 u1, u2의 교점 p = $u1\times u2$이다. 또한 두 점 p1, p2를 지나는 직선의 방정식은 u = $p1\times p2$가 된다. Homogeneous 표현을 이용하면 두 직선의 교점, 두 점을 지나는 직선의 방정식을 외적으로 구할 수 있게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[영상처리 기초] 1. 좌표계(Coordinate System)]]></title>
            <link>https://velog.io/@real_jun9u/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-%EA%B8%B0%EC%B4%88-1.-%EC%A2%8C%ED%91%9C%EA%B3%84Coordinate-System</link>
            <guid>https://velog.io/@real_jun9u/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-%EA%B8%B0%EC%B4%88-1.-%EC%A2%8C%ED%91%9C%EA%B3%84Coordinate-System</guid>
            <pubDate>Sun, 30 Jan 2022 12:53:33 GMT</pubDate>
            <description><![CDATA[<h1 id="좌표계">좌표계</h1>
<p>영상 Geometry에서의 좌표계는1. 월드 좌표계, 2. 카메라 좌표계, 3. 정규 좌표계, 4. 이미지 좌표계가 존재한다. 이 좌표계들을 이해하여야 카메라 Geometry를 이해하기위한 시작이 될 수 있다.</p>
<h2 id="1-월드-좌표계world-coordinate-system">1. 월드 좌표계(World Coordinate System)</h2>
<p>물체의 위치를 표현할 때 기준으로 삼는 실제 공간의 좌표계이다. 월드 좌표계는 문제에 따라 임의로 설정할 수 있는 좌표계이다. 어떤 물체를 기준으로 원점을 설정하고 X,Y,Z축을 잡을 수도 있는 것이다.
$P = (X,Y,Z)$</p>
<h2 id="2-카메라-좌표계camera-coordinate-system">2. 카메라 좌표계(Camera Coordinate System)</h2>
<p>카메라 좌표계는 카메라를 기준으로 한 좌표계로 카메라의 초점을 원점으로 하고 정면 광학축을 Z축, 카메라 오른쪽 방향을 X축, 아래 방향을 Y축으로 한다(오른손 좌표계).
<img src="https://images.velog.io/images/real_jun9u/post/f92eaf4e-ef90-440c-af9d-0e63189b94c7/image.png" alt="">
$P_c=(X_c,Y_c,Z_c)$</p>
<h2 id="3-이미지-좌표계image-coordinate-system">3. 이미지 좌표계(Image Coordinate System)</h2>
<p>이미지 좌표계는 카메라의 이미지 평면에 그려지는 이미지나 사람의 눈에 맺힌 영상에 대한 좌표계로 이미지의 좌상단을 원점으로하고 오른쪽 방향을 X축, 아래 방향을 Y축으로 하는 2차원 좌표계로 한다. 3D 공간의 점 P는 카메라의 초점을 지나 이미지 평면의 한 점 $p_{img}$로 투영된다. 이 때 P와 $p_{img}$를 잇는 직선상의 모든 점은 $p_{img}$가 될 수 있으므로 유일하게 결정할 수 없다. 3D 공간의 점은 평면 상에 유일하게 결정되지만, 평면의 점을 3D로 복원하려면 Depth 정보를 알아야 복원할 수 있다.
$p_{img}=(x,y)$</p>
<h2 id="4-정규-좌표계normalized-image-coordinate-system">4. 정규 좌표계(Normalized Image Coordinate System)</h2>
<p>정규 좌표계는 가상의 좌표계로 카메라의 내부 파라미터(Intrinsic Parameter)의 영향을 제거한 이미지 좌표계로 카메라 초점 거리가 1인 가상의 평면을 정의한다.
정규 이미지 좌표계의 원점은 이미지 좌표계와 달리 이미지 평면의 중점(광학축 과의 교점)이고 좌표축은 u,v로 표시한다.
$p&#39;=(u,v)$
카메라 내부 파라미터를 알면 이미지 좌표계와 정규 좌표계사이 변환이 가능하다.
$p_{img} = Kp&#39;$</p>
<p>$\begin{bmatrix}x \ y \ 1 \end{bmatrix} = \begin{bmatrix}f_x &amp; 0 &amp; c_x \ 0 &amp; f_y &amp; c_y \ 0 &amp; 0 &amp; 1 \end{bmatrix} \begin{bmatrix}u \ v \ 1 \end{bmatrix}$</p>
<p>위 식을 정리하면 아래처럼 변환된다.
$x=f_xu+c_x \ y=f_yv+c_y$</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[영상처리] 카메라 캘리브레이션]]></title>
            <link>https://velog.io/@real_jun9u/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-%EA%B8%B0%EC%B4%88-1.-%EC%B9%B4%EB%A9%94%EB%9D%BC-%EC%BA%98%EB%A6%AC%EB%B8%8C%EB%A0%88%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@real_jun9u/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-%EA%B8%B0%EC%B4%88-1.-%EC%B9%B4%EB%A9%94%EB%9D%BC-%EC%BA%98%EB%A6%AC%EB%B8%8C%EB%A0%88%EC%9D%B4%EC%85%98</guid>
            <pubDate>Sun, 30 Jan 2022 12:20:43 GMT</pubDate>
            <description><![CDATA[<h2 id="카메라-캘리브레이션이란">카메라 캘리브레이션이란?</h2>
<p>실제 3차원 공간을 카메라로 촬영하면 2차원의 이미지가 된다. 3차원의 상이 이미지에 맺힐때에는 카메라의 렌즈, 렌즈와 이미지 센서와의 거리, 렌즈와 이미지 센서와의 각도등의 카메라 내부 구조에 의해 영향을 받는다. 이미지에서 3차원으로 복원하거나, 3차원 상이 투사된 이미지 내의 위치를 알기 위해서는 내부 파라미터를 알아야 가능한데, 이러한 내부 파라미터를 구하는 과정이 카메라 캘리브레이션이다.</p>
<h2 id="캘리브레이션-개요">캘리브레이션 개요</h2>
<p>$$s\begin{bmatrix}x \ y \ 1\end{bmatrix} = \begin{bmatrix}f_x &amp; skew_cf_x &amp; c_x\ 0 &amp; f_y &amp; c_y \ 0 &amp; 0 &amp;1\end{bmatrix} \begin{bmatrix}r_{11} &amp; r_{12} &amp; r_{13} &amp; t_1\ r_{21} &amp; r_{22} &amp; r_{23} &amp; t_2 \ r_{31} &amp; r_{32} &amp; r_{33} &amp; t_3\end{bmatrix} \begin{bmatrix}X \ Y \ Z \ 1\end{bmatrix} = A \begin{bmatrix}R|t\end{bmatrix} \begin{bmatrix}X \ Y \ Z \ 1\end{bmatrix}$$
$$(X,Y,Z)$$는 월드 좌표계상의 3D 좌표이고, $[R|t]$는 월드 좌표계를 카메라 좌표계로 변환시키기 위한 Rotation Matrix, Translation Vector 이 합쳐진 회전/이동 변환행렬이다. A와 비교하여 Extrinsic Parameter 라고도 한다. A는 Intrinsic Parameter로 카메라 내부 파라미터로 이루어진 행렬이다. A와 $[R|t]$를 합쳐서 Camera Matrix, Projection Matrix라고도 한다.
외부 파라미터는 카메라 외부 공간과의 관계를 나타내는 파라미터이고, 내부 파라미터는 카메라의 초점거리, aspect ratio, 이미지 면의 중심점 등 카메라 내부의 파라미터를 의미한다.</p>
<h2 id="카메라-내부-파라미터intrinsic-parameters">카메라 내부 파라미터(Intrinsic Parameters)</h2>
<h3 id="1-초점-거리focal-length--fx-fy">1. 초점 거리(Focal Length) : fx, fy</h3>
<p>카메라 모델에서의 초점 거리는 렌즈 중심(혹은 핀홀)과 이미지센서(이미지 플레인)와의 거리이다. 초점 거리는 mm로 표현되거나 픽셀단위로 표현된다. 픽셀은 이미지 센서의 셀의 크기로, 셀의 크기가 0.1mm이고 초점거리 f = 300 pixel로 표현되면 f = 30mm 가 된다. 초점 거리를 픽셀단위로 표현하는 것은 영상에서의 해석을 용이하게 하기 위함이다.
카메라 모델에서 초점 거리를 fx, fy로 표현하는 경우는 이미지 센서의 물리적인 셀이 가로와 세로의 길이가 같지 않을 수 있기 때문인데, fx는 셀의 가로에 대한 초점 거리의 비, fy는 셀의 세로에 대한 초점 거리의 비가된다. 일반적인 카메라는 셀의 가로,세로 크기가 같아 f = fx = fy로 생각할 수 있다.
초점 거리와 픽셀 크기와의 관계를 통해 해상도에 따른 초점거리에 대해 알 수 있다. 캘리브레이션을 수행했을 때, 이미지 해상도를 $\frac{1}{2}$로 하였을 때 초점 거리도 $\frac{1}{2}$배가 된다. 해상도를 $\frac{1}{2}$로 낮추면 $2\times 2$의 픽셀이 한 픽셀이 되므로 픽셀의 가로,세로가 2배가 되는것과 동일하므로 초점 거리는 $\frac{1}{2}$배가 된다.</p>
<ul>
<li>이미지 센서의 셀이라는 것은 집적되어있는 광학 다이오드를 말하는데, 일정 시간동안 축적된 광량을 전기적 값으로 변환한다.<h3 id="2-주점principal-point--cx-cy">2. 주점(Principal Point) : cx, cy</h3>
주점은 렌즈 중심(혹은 핀홀)에서 이미지 플레인에 내린 수선의 발의 영상좌표로 단위는 픽셀이다. 일반적인 영상 중심과는 다른 의미로 카메라가 오차로 인해 렌즈와 이미지 센서의 수평이 어긋나면 주점과 영상 중심은 달라지게 된다.<h3 id="3-비대칭계수skew-coefficient--skew_c--tanalpha">3. 비대칭계수(Skew Coefficient) : skew_c = $tan\alpha$</h3>
비대칭계수는 이미지 센서의 셀 배열(이미지 플레인)의 y축이 기울어진 정도를 나타낸다. 최근의 카메라 모델에서는 비대칭 오류가 거의 없어 skew_c = 0으로 생각할 수 있다.</li>
</ul>
<h2 id="카메라-내부-파라미터extrinsic-parameters">카메라 내부 파라미터(Extrinsic Parameters)</h2>
<p>카메라 외부 파라미터는 카메라를 어떤 위치에 어떤 방향으로 설치했는지에 따라 다르고, 월드 좌표계를 어떻게 정의했는지에 따라 달라진다. 외부 파라미터(Rotation, Translation)을 구하려면 캘리브레이션을 통해 내부 파라미터를 구한 후, 3D월드좌표-2D영상좌표 매칭 쌍들을 이용하여 구할 수 있다.</p>
<h2 id="핀홀pinhole-카메라-모델">핀홀(Pinhole) 카메라 모델</h2>
<p>핀홀 카메라 모델은 하나의 바늘구멍(Pinhole)을 통해 상이 이미지로 투영되는 모델이다. 여기서 핀홀이 렌즈 중심, 상이 맺히는 평면과의 거리가 초점거리가 된다. 영상처리에서 영상에 대한 기하학적 해석은 핀홀 카메라 모델을 바탕으로 이루어지지만, 이상적인 모델로 실제로는 렌즈에 대한 왜곡등도 고려해야한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[컴퓨터 비전 기초] 스테레오 비전 - Triangulation]]></title>
            <link>https://velog.io/@real_jun9u/%EC%BB%B4%ED%93%A8%ED%84%B0-%EB%B9%84%EC%A0%84-%EA%B8%B0%EC%B4%88-%EC%8A%A4%ED%85%8C%EB%A0%88%EC%98%A4-%EB%B9%84%EC%A0%84-Triangulation</link>
            <guid>https://velog.io/@real_jun9u/%EC%BB%B4%ED%93%A8%ED%84%B0-%EB%B9%84%EC%A0%84-%EA%B8%B0%EC%B4%88-%EC%8A%A4%ED%85%8C%EB%A0%88%EC%98%A4-%EB%B9%84%EC%A0%84-Triangulation</guid>
            <pubDate>Fri, 28 Jan 2022 11:47:41 GMT</pubDate>
            <description><![CDATA[<p>컴퓨터 비전에서 Triangulation은 2개 이상의 이미지에 투영된 3D 공간의 한 지점을 결정하는 프로세스를 말한다. 이미지를 매칭시킬뿐 아니라 뎁스 정보까지 얻을 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JThermo Project] 자재 정보]]></title>
            <link>https://velog.io/@real_jun9u/JThermo-Project-%EC%9E%90%EC%9E%AC-%EC%A0%95%EB%B3%B4</link>
            <guid>https://velog.io/@real_jun9u/JThermo-Project-%EC%9E%90%EC%9E%AC-%EC%A0%95%EB%B3%B4</guid>
            <pubDate>Thu, 27 Jan 2022 15:03:45 GMT</pubDate>
            <description><![CDATA[<h3 id="flir-lepton-35">FLIR Lepton 3.5</h3>
<p>해상도 : 160 x 120
픽셀 크기 : 12um
FOV : 수평 - 57 수직 - 71
f-number : 1.1</p>
<h3 id="logitech-c920">Logitech C920</h3>
<pre><code>dmesg
lsusb
v4l2-ctl --list-devices
v4l2-ctl --list-formats-ext</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[JThermal Project] 개발 일지]]></title>
            <link>https://velog.io/@real_jun9u/JThermo-Project-%EA%B0%9C%EB%B0%9C-%EC%9D%BC%EC%A7%80</link>
            <guid>https://velog.io/@real_jun9u/JThermo-Project-%EA%B0%9C%EB%B0%9C-%EC%9D%BC%EC%A7%80</guid>
            <pubDate>Tue, 25 Jan 2022 00:56:55 GMT</pubDate>
            <description><![CDATA[<h1 id="jthermal-project-소개">JThermal Project 소개</h1>
<p>현재 코로나 상황이 지속되며 악화되고 있는 상황이다. 감염자 수의 증가세는 가라앉지 않고 있으며, 앞으로도 방역에 많이 힘써야한다. 전파를 줄이기 위해서는 감염자를 조기에 발견하여 접촉자 수를 줄여야만 하는데, 현재 이를 위해 대부분의 건물의 입구에 열화상 온도계를 설치하여 발열 검사를 시행하고 있다. 하지만 측정된 온도값들은 겨울철에는 체온보다 상당히 낮게나오는 경우가 많다. 이러한 측정 결과는 발열 증상이 있는 사람의 온도가 정상적인 범주의 사람으로 분류될 수 있음을 뜻하여 측정 방식의 신뢰도에 의문을 제기하게 된다. 적외선 측정 방식에서 이러한 문제를 개선하여 발열자의 검출률을 높이는 것이 이 프로젝트의 목표이다.</p>
<h2 id="분석과-아이디어">분석과 아이디어</h2>
<ol>
<li><p>기존 열화상 온도계의 펌웨어나 소스 코드를 알 수 없어 정확히 어떤 방식으로 측정하는지는 알 수 없었으나, 문의를 통해 들은 내용으로는 열화상 이미지 내에서 가장 높은 온도를 보이는 픽셀 주변의 온도를 평균으로 하여 온도를 출력한다고 한다. 일반적으로 설치된 열화상 온도계들은 얼굴이 화면에 표시된 타원형의 경계에 얼굴을 맞추어야 측정을 하는데, 이러한 경계 속 최대 온도값의 주변 평균 온도를 측정하는 것으로 보인다. 그렇지 않으면 화면 안에 더 높은 온도의 물체가 담기는 상황은 적지 않게 발생할 수 있으므로 경계를 의도적으로 이용하는 것으로 생각된다. 하지만 그렇다고 해도 사람의 얼굴이 정확히 경계와 일치할 수는 없으므로 경계에서 얼굴을 제외한 부분의 온도값이 사람의 얼굴 온도보다 높다면 측정의 결과는 달라지게 될 것이다. 따라서 컬러 이미지에서 얼굴의 윤곽을 만든 후 열화상 이미지와 매칭시켜 배경의 영향을 제거한다.</p>
</li>
<li><p>안면 온도 측정에서 실제 체온보다 낮거나 같은 온도가 측정되는데, 그 중 이마의 온도가 가장 신뢰도가 높다고 알려져 있다. 온도가 낮게 측정되는 경향은 실제 발열자의 측정 온도가 정상 범주로 판단될 가능성을 야기한다. 온도가 낮게 측정되는 것은 실내보다 기온이 낮은 바깥 환경에 노출되어서 안면의 피부 온도가 낮아지기 때문인데, 사람이 얼마나 바깥에서 노출되었는지는 측정하기 쉽지 않다. 안면 온도 저하 문제를 해결하기 위해 안면 온도의 부위별 분포를 분석하여 보정 계수를 정하는 방법을 취한다.</p>
</li>
</ol>
<h2 id="구현-단계">구현 단계</h2>
<h3 id="1-시스템-구성--세팅29">1. 시스템 구성 / 세팅(2/9~)</h3>
<ol>
<li><p>라즈베리파이 4, FLIR Lepton 3.5 적외선 센서가 마운트 된 PureThermal2 보드, 파이 카메라 모듈을 3D 프레임에 마운트하여 HW를 세팅한다.</p>
</li>
<li><p>라즈베리파이의 OS는 Raspbian Buster(2022-01-28)를 설치.</p>
</li>
<li><p>파이썬 버전은 Default인 3.7이 아닌 3.8.3으로 세팅하기 위해 3.8.3을 설치하고 venv로 가상 환경을 관리한다.</p>
<pre><code class="language-bash">sudo apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libsqlite3-dev libreadline-dev libffi-dev wget libbz2-dev
</code></pre>
</li>
</ol>
<h1 id="python-383-설치">Python 3.8.3 설치</h1>
<p>wget <a href="https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz">https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz</a>
tar -xf Python-3.8.3.tgz
cd Python-3.8.3
./configure --enable-optimizations
make
sudo make altinstall</p>
<h1 id="가상환경-만들기">가상환경 만들기</h1>
<p>python3.8 -m venv .env3_8
source .env/bin/activate
pip install ipython
pip install ipykernel
pip install opencv-python</p>
<pre><code>
4. 파이 카메라 모듈 v2 연결후 테스트
```bash
sudo raspi-config
# Interface - Enable Camera
vcgencmd get_camera # supported=1, detected=1이면 완료
raspistill -o test.jpg</code></pre><ol start="5">
<li><p>Lepton이 부착된 PureThermal2를 연결하고 필요 라이브러리 설치</p>
<pre><code class="language-bash"># PureThermal Project 설치
https://github.com/groupgets/purethermal1-uvc-capture.git
# libuvc 설치
sudo apt-get install cmake
sudo apt-get install libusb-1.0.0-dev
sudo apt-get install libjpeg-dev
git clone https://github.com/groupgets/libuvc
cd libuvc
mkdir build
cd build
cmake ..
make &amp;&amp; sudo make install
sudo ldconfig -v</code></pre>
</li>
<li><p>AHT10 온습도 센서 세팅 후 테스트</p>
<pre><code class="language-bash">pip install smbus
python aht10.py</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/4cc56931-6fea-445f-b1f8-ba68d0d869da/image.png" alt=""></p>
</li>
</ol>
<h3 id="2-안면-부위당-온도-측정">2. 안면 부위당 온도 측정</h3>
<p>안면 온도에서 실체온을 추정할 때에 정확한 추정을 위해서는 안면의 부위별 온도를 측정하여야 한다. 이를 위해서는 실화상 이미지에서 안면 추출 후 부위를 나누어야한다.</p>
<ol>
<li>마스크, 안경이 없는 얼굴에서 부위 추출</li>
<li>1에서 성공한 방법에서 마스크, 안경이 있는 얼굴에서 부위 추출.</li>
</ol>
<pre><code class="language-bash"># MediaPipe 설치
git clone https://github.com/google/mediapipe.git
# Bazel 설치
sudo apt-get install -y openjdk-8-jdk
git clone https://github.com/PINTO0309/Bazel_bin.git
cd Bazel_bin/3.7.2/armhf/
./install.sh
which bazel # Bazel 설치 확인
sudo apt-get install mesa-common-dev libegl1-mesa-dev libgles2-mesa-dev -y</code></pre>
<pre><code class="language-bash"># mediapipe/examples/desktop/hello_world/BUILD의 cc_binary에 추가
linkopts = [
    &quot;-latomic&quot;
]

cd ~/mediapipe
export GLOG_logtostderr=1
bazel run --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 mediapipe/examples/desktop/hello_world:hello_world</code></pre>
<h3 id="3-열화상-이미지와-실화상-이미지의-매칭">3. 열화상 이미지와 실화상 이미지의 매칭</h3>
<p>열화상 이미지에서는 환경에 따라 안면 추출이 불가한 경우가 발생하므로 실화상 이미지에서 안면을 추출하여 열화상 이미지로 적용해야하는데, 일반적으로 적외선 카메라의 해상도가 실화상 카메라의 해상도보다 작고, 두 카메라의 시야각이 다르며 동일한 위치, 방향이 아니므로 두 이미지를 매칭하기 위해서는 이러한 문제를 해결해야한다.</p>
<ol>
<li>먼저 동일한 컬러 카메라 2대의 이미지를 가지고 이미지 매칭을 해본다. 물체를 서로 다른 각도에서 바라본 두 이미지에서 특징점을 매칭한다.</li>
<li>1에서 성공한 방법을 서로 다른 컬러 카메라끼리의 이미지를 가지고 1을 반복한다.</li>
<li>2에서 성공한 방법을 적외선 카메라와 컬러 카메라로 1을 반복한다.</li>
</ol>
<p>위의 과정에서 사용한 방법은 아래를 참고하였다.</p>
<h3 id="4-적외선-센서-캘리브레이션">4. 적외선 센서 캘리브레이션</h3>
<p>1,2의 과정을 거쳐 추출된 열화상 이미지에서 온도를 측정하는데, 측정된 온도가 실제 해당 부위 온도와 일치하는 지에 대해 조사하고 보정하는 과정이 필요하다.</p>
<ol>
<li>적외선 센서에서 1m 전방에 물병의 뚜껑이 보일 수 있게 구성하고, 물의 온도를 조절하며 물리적 측정한 온도와 적외선 센서에서 측정된 온도를 기록한다.</li>
<li>측정된 데이터로 선형 회귀 방정식을 구하여 온도를 보정한다.</li>
</ol>
<h2 id="실험-hardware-구성">실험 Hardware 구성</h2>
<table>
<thead>
<tr>
<th>Number</th>
<th>Device</th>
<th>Information</th>
<th>Price(₩)</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>RASPBERRY PI 4 MODEL B 8G</td>
<td><a href="https://www.devicemart.co.kr/goods/view?no=12553062">Link</a></td>
<td>135,000</td>
</tr>
<tr>
<td>2</td>
<td>RASPBERRY PI CAMERA MODULE V2</td>
<td><a href="https://www.devicemart.co.kr/goods/view?no=1077951">Link</a></td>
<td>35,000</td>
</tr>
<tr>
<td>3</td>
<td>FLIR Lepton 3.5</td>
<td><a href="https://www.digikey.kr/ko/products/detail/flir-lepton/500-0771-01/7606616">Link</a></td>
<td>190,851</td>
</tr>
<tr>
<td>4</td>
<td>PureThermal 2 - Flir Lepton Smart I/O Module</td>
<td><a href="https://www.digikey.kr/ko/products/detail/groupgets-llc/PURETHERMAL-2/9866290">Link</a></td>
<td>126,807</td>
</tr>
<tr>
<td>5</td>
<td>3D Frame(Self-Designed)</td>
<td></td>
<td></td>
</tr>
<tr>
<td>1. RASPBERRY PI 4 MODEL B 8G</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><img src="https://images.velog.io/images/real_jun9u/post/1a5427f5-b712-471a-8029-a81709ebb901/image.png" alt=""></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><img src="https://images.velog.io/images/real_jun9u/post/8536e17f-9fb3-4bb2-9062-4db727355170/image.png" alt=""></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>2. RASPBERRY PI CAMERA MODULE V2</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><img src="https://images.velog.io/images/real_jun9u/post/d3e0b997-d413-4277-a695-5a8179bb5792/image.png" alt=""></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>3. PureThermal 2 - Flir Lepton Smart I/O Module</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><img src="https://images.velog.io/images/real_jun9u/post/e5b1f496-fa50-4820-be2a-899695d5cea2/image.png" alt=""></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h3 id="타임-라인">타임 라인</h3>
<ul>
<li>2022-01-24 개발 일지 작성 시작. 자재 조사 후 3D프레임 모델링 시작</li>
<li>2022-01-25 3D 모델링 작업 진행. 세부 구조 스케치
<img src="https://images.velog.io/images/real_jun9u/post/283261ef-8041-4949-8935-5d15455246d4/image.png" alt=""></li>
<li>2022-01-27 3D 모델링 완료. CATPart -&gt; STL -&gt; gcode 변환 완료. 밑면은 3시간, 뚜껑은 9시간 소요 예정으로 이틀에 걸쳐 출력 예정.</li>
<li>2022-02-09 3D 모델 수정하여 재출력.(v2) 가상환경, 파이 카메라 세팅 완료.</li>
<li>2022-02-10 3D 프레임 조립 하여 HW 세팅 마침. 라즈베리파이 OS 라즈비안 -&gt; Ubuntu Desktop 21.10으로 변경</li>
</ul>
<h3 id="깃허브">깃허브</h3>
<ul>
<li>프로젝트 : <a href="https://github.com/realJun9u/JThermal">https://github.com/realJun9u/JThermal</a></li>
</ul>
<h3 id="참고">참고</h3>
<ul>
<li>FLIR 열화상 카메라는 시간이 지나도 보정 상태를 유지할 수 있습니다. 그렇기 때문에, FDA가 권장하는 주변 드리프트 및 지정 시간 범위 내 안정성 사양 기준 (0.2 °C 미만)을 충족하기 위해 카메라 시야에 굳이 기준 블랙바디를 배치할 필요가 없습니다. <a href="https://www.flirkorea.com/discover/public-safety/do-i-need-a-blackbody-for-skin-temperature-screening/#download-now">https://www.flirkorea.com/discover/public-safety/do-i-need-a-blackbody-for-skin-temperature-screening/#download-now</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenCV 13. 이미지 피라미드]]></title>
            <link>https://velog.io/@real_jun9u/OpenCV-13.-%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%94%BC%EB%9D%BC%EB%AF%B8%EB%93%9C</link>
            <guid>https://velog.io/@real_jun9u/OpenCV-13.-%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%94%BC%EB%9D%BC%EB%AF%B8%EB%93%9C</guid>
            <pubDate>Sun, 16 Jan 2022 13:29:07 GMT</pubDate>
            <description><![CDATA[<h2 id="이미지-피라미드image-pyramids">이미지 피라미드(Image Pyramids)</h2>
<p>이미지의 스케일과 해상도를 조절하는 작업
전체 이미지에서 특정 이미지를 찾을 때 해상도를 다단계로 만들어 탐색. 동일한 이미지를 해상도와 스케일에 따라 나눈 이미지 세트를 이미지 피라미드라한다. 상위 단계로 갈수록 해상도는 작고 스케일이 높다.</p>
<h3 id="1-gaussian-pyramids">1. Gaussian Pyramids</h3>
<p>가우시안 피라미드는 크기 조절시 Gaussian Filter를 사용한다
downsampling : 상위 단계 이미지 생성 . 이미지를 가우시안 블러처리 후 짝수 행과 열을 제거
해상도 $M\times N$ 에서 $M/2\times N/2$ 가 되어 1/4 크기가 된다.(Octave)
upsampling : 하위 단계 이미지 생성. 상위 단계의 이미지에서 짝수 열과 행에 픽셀을 추가후 이미지를 블러처리하여 만든다.</p>
<pre><code class="language-python">cv2.pyrDown(src[,dst[,dstsize[,borderType]]]) -&gt; dst
pyrDown은 Downsample 하기 전에 5X5 가우시안 필터를 적용하여 블러 처리한다.
dstsize : 출력 이미지 크기. 기본적으로 Octave로 계산된다.</code></pre>
<pre><code class="language-python">cv2.pyrUp(src[,dst[,dstsize[,borderType]]]) -&gt; dst
pyrUp은 Upsample한 후 위의 가우시안 필터같은 커널에 4를 곱하여 Upsamle이미지에 합성곱한다.</code></pre>
<pre><code class="language-python">import cv2
import matplotlib.pyplot as plt

img = cv2.imread(&#39;balloons1.jpg&#39;)

img_down = cv2.pyrDown(img)
img_up = cv2.pyrUp(img)

cv2.imshow(&#39;img&#39;,img)
cv2.imshow(&#39;img_down&#39;,img_down)
cv2.imshow(&#39;img_up&#39;,img_up)
cv2.waitKey(0)
cv2.destroyAllWindows()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/ca7e6c84-9cab-42c3-b439-3ead46da331a/pyrdown_up.png" alt=""></p>
<h3 id="2-laplacian-pyramid">2. Laplacian Pyramid</h3>
<p>가우시안 피라미드로 부터 생성된다.
라플라시안 필터는 이미지에서 고주파 통과 필터로 피라미드의 각 레벨에서 경계선 이미지를 얻을 수 있다.
라플라시안 피라미드의 레벨은 해당 레벨의 가우시안 피라미드 이미지와 상위 단계의 이미지를 확장시킨 이미지의 차이로 구성된다.</p>
<ol>
<li>원본 이미지로 상위 단계 생성</li>
<li>만들어진 상위 단계에서 하위 단계 생성</li>
<li>원본과 2에서 만들어진 이미지 크기를 resize를 통해 맞춘 후 차이를 구한다.<pre><code class="language-python">import cv2
import matplotlib.pyplot as plt
</code></pre>
</li>
</ol>
<p>img = cv2.imread(&#39;emoji1.png&#39;)
img_gad = cv2.pyrDown(img)
img_gau = cv2.pyrUp(img_gad)</p>
<p>print(img.shape)
print(img_gau.shape)</p>
<p>img_lap = cv2.subtract(img,img_gau)</p>
<p>cv2.imshow(&#39;Original&#39;,img)
cv2.imshow(&#39;Gaussian Down&#39;,img_gad)
cv2.imshow(&#39;Gaussian Up&#39;,img_gau)
cv2.imshow(&#39;Laplacian&#39;,img_lap)
cv2.waitKey(0)
cv2.destroyAllWindows()</p>
<p>```
<img src="https://images.velog.io/images/real_jun9u/post/5c0e8d64-d20b-4eb0-aa70-480ec74e06b0/pyramid_Laplacian.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenCV 12. 이미지 그레디언트]]></title>
            <link>https://velog.io/@real_jun9u/OpenCV-12.-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EA%B7%B8%EB%A0%88%EB%94%94%EC%96%B8%ED%8A%B8</link>
            <guid>https://velog.io/@real_jun9u/OpenCV-12.-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EA%B7%B8%EB%A0%88%EB%94%94%EC%96%B8%ED%8A%B8</guid>
            <pubDate>Sun, 16 Jan 2022 13:15:37 GMT</pubDate>
            <description><![CDATA[<h2 id="이미지-그레디언트image-gradients">이미지 그레디언트(Image Gradients)</h2>
<p>이미지 내에서 픽셀값의 변화가 큰 경계선, 모서리 부분을 찾는데 쓰인다.</p>
<h3 id="1-sobel-scharr-filter">1. Sobel, Scharr Filter</h3>
<p>Gaussian Smoothing과 미분을 이용한 방법으로 노이즈가 있는 이미지에 적용 가능하다.
1차 미분연산으로 X축과 Y축을 각각 미분하는 방법으로 경계를 계산한다.
미분 필터는 가로, 세로가 같고 홀수이어야 하며 중심을 기준으로 상하좌우 대칭(Roberts 제외)이고 모든 수의 합은 0이다.</p>
<pre><code class="language-python">cv2.Sobel(src,ddepth,dx,dy[,dst[,ksize[,dcale[,delta[,borderType]]]]])
ddepth : 출력 이미지의 데이터 형태. -1이면 입력 이미지와 동일하게 출력
dx,dy: x,y축 미분 차수
ksize : 커널 사이즈. Sobel Filter는 1,3,5,7이 가능하고 Default는 3이다.</code></pre>
<ol>
<li>Sobel Filter : ksize=3이고 dx=1 이면  $\begin{bmatrix} -1&amp;0&amp;1\-2&amp;0&amp;2\-1&amp;0&amp;1 \end{bmatrix}$ 필터가 적용되고  dy=1 이면 $\begin{bmatrix} -1&amp;-2&amp;-1\0&amp;0&amp;0\1&amp;2&amp;1 \end{bmatrix}$ 필터가 적용된다</li>
<li>Scharr Filter : $\begin{bmatrix} -3&amp;0&amp;3\-10&amp;0&amp;10\-3&amp;0&amp;3 \end{bmatrix}$, $\begin{bmatrix} -3&amp;-10&amp;-3\0&amp;0&amp;0\3&amp;10&amp;3 \end{bmatrix}$으로 Sobel Filter에서 숫자만 다르다. ksize = -1(cv2.FILTER_SCHARR)로 설정하면 Sobel Filter가 아닌 Scharr Filter가 적용된다.<pre><code class="language-python">import cv2
import numpy as np
import matplotlib.pyplot as plt
</code></pre>
</li>
</ol>
<p>img = cv2.imread(&#39;city1.jpg&#39;,cv2.IMREAD_GRAYSCALE)</p>
<p>sobelX = cv2.Sobel(img,-1,1,0,ksize=3)
sobelY = cv2.Sobel(img,-1,0,1,ksize=3)
sobel = sobelX + sobelY</p>
<p>scharrX = cv2.Sobel(img,-1,1,0,ksize=cv2.FILTER_SCHARR)
scharrY = cv2.Sobel(img,-1,0,1,ksize=cv2.FILTER_SCHARR)
scharr = scharrX+scharrY</p>
<p>titles = [&#39;Original&#39;,&#39;SobelX&#39;,&#39;SobelY&#39;,&#39;Sobel&#39;,&#39;ScharrX&#39;,&#39;ScharrY&#39;,&#39;Scharr&#39;]
images = [img,sobelX,sobelY,sobel,scharrX,scharrY,scharr]
plt.figure(figsize=(12,12))
plt.subplot(3,3,2)
plt.imshow(images[0])
plt.title(titles[0])
plt.axis(&#39;off&#39;)
for i in range(1,len(images)):
    plt.subplot(3,3,i+3)
    plt.imshow(images[i])
    plt.title(titles[i])
    plt.axis(&#39;off&#39;)
plt.tight_layout()
plt.savefig(&#39;Sobel_Scharr.jpg&#39;)
plt.show()</p>
<pre><code>![](https://images.velog.io/images/real_jun9u/post/0c65b5d1-fb0c-458b-ae2f-45d8249ef6cb/Sobel_Scharr.jpg)
두 필터 모두 X축 방향 미분 결과를 보면 세로 선이 검출이 되고, Y축 방향 미분 결과는 가로 선이 검출이 된다. 따라서 두 이미지를 합쳐 오른쪽의 경계 검출 결과가 된다. Sobel Filter가 중앙에서 멀어질 수록 검출이 안되는 현상을 Scharr Filter에서는 해결이 되었다고 한다.

### 2. Laplacian Filter
Sobel,Scharr Filter와 달리 Gradient를 2차 미분하여 원본과 합성곱하는 필터이다.
1차 미분의 크기는 경계의 존재 여부, 2차 미분의 부호는 경계선의 화소가 밝은 부분에 있는지 어두운 부분에 있는지 결정하는데 사용된다. 2차 미분 방식을 사용하면 저주파 성분에 해당하는 값들이 소거가 되고 고주파는 선명하게 나타나므로 경계선 부분을 강조할 수 있다.
Laplacian Filter = $\begin{bmatrix} 0&amp;1&amp;0\\1&amp;-4&amp;1\\0&amp;1&amp;0 \end{bmatrix}$, $\begin{bmatrix} 1&amp;1&amp;1\\1&amp;-8&amp;1\\1&amp;1&amp;1 \end{bmatrix}$
```python
cv2.Laplacian(src,ddepth,[,dst[,ksize[,scale[,delta[,borderType]]]]])
ksize : 31이하의 홀수만 가능. Default는 1이고 앞의 필터, 3일 때는 뒤의 필터가 적용된다.</code></pre><p>Laplacian Filter는 잡음에 민감하여 Gaussian Filtering으로 노이즈를 제거하고 적용하는 LoG(Laplacian of Gaussian)방법을 사용한다.</p>
<pre><code class="language-python">import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread(&#39;city1.jpg&#39;,cv2.IMREAD_GRAYSCALE)

img_laplacian1 = cv2.Laplacian(img,-1,ksize=1)
img_laplacian3 = cv2.Laplacian(img,-1,ksize=3)
# numpy로 만든 Laplacian Filter
laplacian_filter1 = np.array([[0,1,0],[1,-4,1],[0,1,0]])
laplacian_filter3 = np.array([[1,1,1],[1,-8,1],[1,1,1]])
img_laplacian1_n = cv2.filter2D(img,-1,laplacian_filter1)
img_laplacian3_n = cv2.filter2D(img,-1,laplacian_filter3)
# Sobel Filter로 2번 미분
img_sobelX = cv2.Sobel(img,-1,1,0,ksize=3)
img_sobelY = cv2.Sobel(img,-1,0,1,ksize=3)
img_sobel = img_sobelX + img_sobelY

titles = [&#39;Original&#39;,&#39;Sobel&#39;,&#39;Laplacian_1&#39;,&#39;Laplacian_n1&#39;,&#39;Laplacian_3&#39;,&#39;Laplacian_n3&#39;]
images = [img,img_sobel,img_laplacian1,img_laplacian1_n,img_laplacian3,img_laplacian3_n]
plt.figure(figsize=(8,8))
for i in range(len(images)):
    plt.subplot(3,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
    plt.axis(&#39;off&#39;)
plt.tight_layout()
plt.savefig(&#39;Laplacian.jpg&#39;)
plt.show()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/762701a5-d580-42f8-b9c2-2adbb24a3497/Laplacian.jpg" alt="">
결과 이미지에서 왼쪽의 결과는 cv2.Laplacian함수를 이용해 생성한 이미지 이고, 오른쪽의 결과는 numpy 배열로 Laplacian Filter를 생성하여 적용한 결과로, 동일한 결과를 보인다.</p>
<h3 id="3-canny-edge-detection">3. Canny Edge Detection</h3>
<p>경계선 검출에서 가장 많이 사용하는 알고리즘이다.</p>
<ol>
<li>Gaussian Filter로 이미지의 잡음을 제거한다.</li>
<li>Sobel Filter로 Gradient의 강도를 구한다.</li>
<li>Non-maximum Suppression을 적용하여 Edge가 아닌 픽셀 제거</li>
<li>Hysteresis Thresholding 방식을 적용한다. maxVal, minVal을 설정하고 maxVal 이상은 Strong Edge, min과 max사이는 Weak Edge, minVal 이하는 제거한다.<pre><code class="language-python">cv2.Canny(img,threshold1,threshold2[,edges[,apertureSize[,L2gradient]]]) -&gt; edges
threshold1 : Hysteresis를 위한 임계값 1
threshold2 : Hysteresis를 위한 임계값 2
두 임계값 중 큰 값이 maxVal, 작은 값이 minVal이 된다.
일반적으로 threshold1이 threshold2 보다 작게 한다.
apetureSize : Sobel Filter의 크기. Sobel 함수처럼 3,5,7만 지정 가능</code></pre>
<pre><code class="language-python">import cv2
import numpy as np
import matplotlib.pyplot as plt
</code></pre>
</li>
</ol>
<p>img = cv2.imread(&#39;city1.jpg&#39;,cv2.IMREAD_GRAYSCALE)</p>
<p>img_canny1 = cv2.Canny(img,50,200)
img_canny2 = cv2.Canny(img,100,200)
img_canny3 = cv2.Canny(img,170,200)</p>
<p>titles = [&#39;Original&#39;,&#39;Canny1&#39;,&#39;Canny2&#39;,&#39;Canny3&#39;]
images = [img,img_canny1,img_canny2,img_canny3]
plt.figure(figsize=(8,8))
for i in range(len(images)):
    plt.subplot(2,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
    plt.axis(&#39;off&#39;)
plt.tight_layout()
plt.savefig(&#39;Canny.jpg&#39;)
plt.show()</p>
<pre><code>![](https://images.velog.io/images/real_jun9u/post/68f35918-92b0-4ce2-801c-c289a099ec61/Canny.jpg)
```python
import cv2
import numpy as np
import matplotlib.pyplot as plt

def nothing(x):
    pass
def edge_detection_img():
    img = cv2.imread(&#39;city1.jpg&#39;,cv2.IMREAD_GRAYSCALE)
    cv2.namedWindow(&#39;Edge Detection&#39;)
    cv2.createTrackbar(&#39;low threshold&#39;,&#39;Edge Detection&#39;,0,255,nothing)
    cv2.createTrackbar(&#39;high threshold&#39;,&#39;Edge Detection&#39;,0,255,nothing)
    cv2.imshow(&#39;Edge Detection&#39;,img)

    while True:
        if cv2.waitKey(1) &amp; 0xFF == 27:
            break
        low = cv2.getTrackbarPos(&#39;low threshold&#39;,&#39;Edge Detection&#39;)
        high = cv2.getTrackbarPos(&#39;high threshold&#39;,&#39;Edge Detection&#39;)

        if low &gt; high:
            print(&#39;Low Value must be lower than High Value&#39;)
        elif low == high:
            cv2.imshow(&#39;Edge Detection&#39;,img)
        else:
            img_canny = cv2.Canny(img,low,high)
            cv2.imshow(&#39;Edge Detection&#39;,img_canny)
    cv2.destroyAllWindows()

edge_detection_img()</code></pre><p><img src="https://images.velog.io/images/real_jun9u/post/acea737a-706d-4c0d-94bc-643f391f23c6/ezgif.com-gif-maker%20(5).gif" alt=""></p>
<pre><code class="language-python">import cv2
import numpy as np
import matplotlib.pyplot as plt

def nothing(x):
    pass
def edge_detection_video():
    try:
        print(&quot;비디오 재생&quot;)
        cap = cv2.VideoCapture(1)
        cv2.namedWindow(&#39;Edge Detection&#39;)
        cv2.createTrackbar(&#39;low threshold&#39;,&#39;Edge Detection&#39;,0,255,nothing)
        cv2.createTrackbar(&#39;high threshold&#39;,&#39;Edge Detection&#39;,0,255,nothing)
    except:
        print(&quot;비디오 재생 실패&quot;)
        return

    while True:
        ret, frame = cap.read()
        if ret:
            frame = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
            if cv2.waitKey(5) &amp; 0xFF == 27:
                break
            low = cv2.getTrackbarPos(&#39;low threshold&#39;,&#39;Edge Detection&#39;)
            high = cv2.getTrackbarPos(&#39;high threshold&#39;,&#39;Edge Detection&#39;)

            if low &gt; high:
                print(&#39;Low Value must be lower than High Value&#39;)
            elif low == high:
                cv2.imshow(&#39;Edge Detection&#39;,frame)
            else:
                img_canny = cv2.Canny(frame,low,high)
                cv2.imshow(&#39;Edge Detection&#39;,img_canny)
        else:
            print(&quot;비디오 종료&quot;)
            break
    cv2.destroyAllWindows()
    cap.release()

edge_detection_video()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/dd12c27f-3b80-4510-9d48-e81be02fdca0/ezgif.com-gif-maker%20(7).gif" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenCV 11. 이미지 형태학적 변환]]></title>
            <link>https://velog.io/@real_jun9u/OpenCV-11.-%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%98%95%ED%83%9C%ED%95%99%EC%A0%81-%EB%B3%80%ED%99%98</link>
            <guid>https://velog.io/@real_jun9u/OpenCV-11.-%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%98%95%ED%83%9C%ED%95%99%EC%A0%81-%EB%B3%80%ED%99%98</guid>
            <pubDate>Sat, 15 Jan 2022 10:52:40 GMT</pubDate>
            <description><![CDATA[<h2 id="이미지-형태학적-변환morphological-tranformation">이미지 형태학적 변환(Morphological Tranformation)</h2>
<p>Morphological Transformation은 이미지를 Segmentation하여 단순화,제거,보정을 통해 형태를 파악하는 목적으로 사용된다. 일반적으로 Binary나 Grayscale Image에 사용이 된다. 사용하는 방법은 Dilation(팽창),Erosion(침식)과 이 두개를 조합한 Opening,Closing이 있다. 입력에는 원본 이미지와 이미지에 적용되는 Structuring Elment(커널)이 있다.</p>
<h3 id="structuring-element">Structuring Element</h3>
<p>커널과 같은 역할을 하는 Structuring Element는 cv2.getStructuringElement를 이용해 구할 수 있다.</p>
<pre><code>cv2.getStructuringElement(shape,ksize[,anchor[) -&gt; retval</code></pre><ol>
<li>shape : 커널의 모양 (타입 : cv::MorphShapes)<ul>
<li>cv2.MORPH_CROSS : 십자가형</li>
<li>cv2.MORPH_ELLIPSE : 타원형</li>
<li>cv2.MORPH_RECT : 직사각형</li>
</ul>
</li>
<li>ksize : 커널의 크기</li>
<li>anchor : 커널의 기준점. default(-1,-1)은 중심을 기준점으로 한다. 이 값은 십자가형의 커널을 사용할 때만 영향이 있다.</li>
</ol>
<pre><code>cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5),anchor = (1,1))</code></pre><p><img src="https://images.velog.io/images/real_jun9u/post/ce4d3aa6-8a26-446f-9d6e-ae87836b4328/image.png" alt=""></p>
<pre><code>cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))</code></pre><p><img src="https://images.velog.io/images/real_jun9u/post/ddac5ad5-5495-4aa5-8835-cbecbcdf4ae4/image.png" alt=""></p>
<pre><code>cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))</code></pre><p><img src="https://images.velog.io/images/real_jun9u/post/bdb82bad-81db-4d09-94a7-35ab5045be95/image.png" alt=""></p>
<h3 id="1-erosion침식">1. Erosion(침식)</h3>
<p>각 픽셀에 Structuring Element를 적용하여 하나라도 0이 있으면 중심 픽셀을 제가한다.
작은 오브젝트를 제거하는데에 효과가 있다.
아래 결과를 보면 검은색 영역이 더 흰색 영역을 침식한다.
cv2.erode(src,kernel[,dst[,anchor[,iterations[,borderType[,borderValue]]]]])
kernel : cv2.getStructuringElement()로 생성한 Structuring Element
anchor : Structuring Element 안에서 사용할 기준점
iterations : 침식 반복 횟수</p>
<pre><code class="language-python">import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread(&#39;cartoon1.png&#39;)
ret, img = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)

kernel = []
kernel.append(cv2.getStructuringElement(cv2.MORPH_RECT,(11,11)))
kernel.append(cv2.getStructuringElement(cv2.MORPH_CROSS,(11,11)))
kernel.append(cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(11,11)))
titles = [&#39;Rectangle&#39;,&#39;Cross&#39;,&#39;Ellipse&#39;]

plt.figure(figsize=(8,8))
plt.subplot(2,2,1)
plt.imshow(img)
plt.title(&#39;Original&#39;)
plt.axis(&#39;off&#39;)

for i in range(3):
    img_erosion = cv2.erode(img,kernel[i])
    plt.subplot(2,2,i+2)
    plt.imshow(img_erosion)
    plt.title(titles[i])
    plt.axis(&#39;off&#39;)
plt.tight_layout()
plt.savefig(&#39;erosion.png&#39;)
plt.show()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/89e4b732-c54a-481c-8521-758b3a66ab1c/erosion.png" alt=""></p>
<h3 id="2-dilation팽창">2. Dilation(팽창)</h3>
<p>Erosion과 반대로 하나라도 1이면 픽셀을 1로 만든다.
Dilation을 적용하면 흰색 영역이 반대로 더 넓어진다.
경계가 부드러워지고 구멍이 메꿔진다.
cv2.dilate(src,kernel,[,dst[,anchor[,iterations[,borderType[,borderValue]]]]])</p>
<pre><code class="language-python">import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread(&#39;cartoon1.png&#39;)
ret, img = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)

kernel = []
ksize = 5
kernel.append(cv2.getStructuringElement(cv2.MORPH_RECT,(ksize,ksize)))
kernel.append(cv2.getStructuringElement(cv2.MORPH_CROSS,(ksize,ksize)))
kernel.append(cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(ksize,ksize)))
titles = [&#39;Rectangle&#39;,&#39;Cross&#39;,&#39;Ellipse&#39;]

plt.figure(figsize=(8,8))
plt.subplot(2,2,1)
plt.imshow(img)
plt.title(&#39;Original&#39;)
plt.axis(&#39;off&#39;)

for i in range(3):
    img_dilation = cv2.dilate(img,kernel[i])
    plt.subplot(2,2,i+2)
    plt.imshow(img_dilation)
    plt.title(titles[i])
    plt.axis(&#39;off&#39;)
plt.tight_layout()
plt.savefig(&#39;dilation.png&#39;)
plt.show()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/00f91205-4432-4fb9-a90a-c0014d1e5ab0/dilation.png" alt=""></p>
<h3 id="3-opening--closing">3. Opening &amp; Closing</h3>
<p>Opening : 이미지에 Erosion 적용 후 Dilation 적용. 점 잡음이나 작은 물체 제거
Closing : 이미지에 Dilation 적용 후 Erosion 적용. 영역끼리 붙어 전체 윤곽 파악
cv2.morphologyEx(src,op,kernel,[,dst[,anchor[,iterations[,borderType[,borderValue]]]]])
op : Morphological 연산의 종류 (타입 : cv::MorphTypes)</p>
<ol>
<li>cv2.MORPH_OPEN : cv2.dilate(cv2.erode(src))</li>
<li>cv2.MORPH_CLOSE : cv2.erode(cv2.dilate(src))</li>
<li>cv2.MORPH_GRADIENT : cv2.dilate(src) - src.erode(src)</li>
<li>cv2.MORPH_TOPHAT : src - opening</li>
<li>cv2.MORPH_BLACKHAT : closing - src<pre><code class="language-python">import cv2
import numpy as np
import matplotlib.pyplot as plt
</code></pre>
</li>
</ol>
<p>img = cv2.imread(&#39;cartoon1.png&#39;)
ret, img = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)</p>
<p>kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
img_opening = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
img_closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)
img_gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
img_tophat = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
img_blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)</p>
<p>titles = [&#39;Original&#39;,&#39;Opening&#39;,&#39;Closing&#39;,&#39;Gradient&#39;,&#39;Tophat&#39;,&#39;Blackhat&#39;]
images = [img,img_opening,img_closing,img_gradient,img_tophat,img_blackhat]</p>
<p>plt.figure(figsize=(8,8))</p>
<p>for i in range(len(images)):
    plt.subplot(2,3,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
    plt.axis(&#39;off&#39;)
plt.tight_layout()
plt.savefig(&#39;morphology.png&#39;)
plt.show()</p>
<p>```
<img src="https://images.velog.io/images/real_jun9u/post/c48ce574-1cee-41f5-aab7-75fcbf87d67d/morphology.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenCV 10. 이미지 필터링]]></title>
            <link>https://velog.io/@real_jun9u/OpenCV-10.-%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%95%84%ED%84%B0%EB%A7%81-0dzro9fb</link>
            <guid>https://velog.io/@real_jun9u/OpenCV-10.-%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%95%84%ED%84%B0%EB%A7%81-0dzro9fb</guid>
            <pubDate>Sat, 15 Jan 2022 09:41:33 GMT</pubDate>
            <description><![CDATA[<h3 id="이미지-필터링">이미지 필터링</h3>
<p>이미지도 음성 신호처럼 주파수로 표현이 가능하다. 고주파는 밝기의 변화가 많은 곳, 즉 경계선 영역에서 나타나고 일반적인 배경은 저주파로 나타난다. 이를 바탕으로 고주파를 제거하면 Blur처리가 되고, 저주파를 제거하면 대상의 영역을 확인할 수 있다.
LPF를 적용하면 노이즈 제거나 Blur처리를 할 수 있고, HPF를 적용하면 경계선을 찾을 수 있다.</p>
<h4 id="1-averaging">1. Averaging</h4>
<p>Box 형태의 커널을 이미지에 적용한 후 평균값을 Box의 중심점에 적용
cv2.blur(src,ksize) -&gt; dst : 위 예제와 동일한 역할
ksize는 튜플 형태 (3,3 등)</p>
<pre><code class="language-python">import cv2
import numpy as np

def nothing(x):
    pass
img = cv2.imread(&#39;squirrel1.jpg&#39;)

cv2.namedWindow(&#39;Image&#39;)
cv2.createTrackbar(&#39;K&#39;,&#39;Image&#39;,1,20,nothing)

while True:
    if cv2.waitKey(1) &amp; 0xFF == 27:
        break
    k = cv2.getTrackbarPos(&#39;K&#39;,&#39;Image&#39;)
    if k == 0:
        k = 1
    kernel = np.ones((k,k),np.float32) / k**2
    dst = cv2.filter2D(img,-1,kernel)

    cv2.imshow(&#39;Image&#39;,dst)

cv2.destroyAllWindows()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/5fafacb4-dd09-4291-89e7-d1dc0288d8ee/ezgif.com-gif-maker%20(6).gif" alt=""></p>
<pre><code class="language-python"># 1.Averaging Blur
import cv2
import numpy as np

img = cv2.imread(&#39;emoji1.png&#39;)
b,g,r = cv2.split(img)
img = cv2.merge([r,g,b])

img_blur = cv2.blur(img,(7,7))

images = [img,img_blur]
titles = [&#39;Original&#39;,&#39;Box Blur(7X7)&#39;]

plt.figure(figsize=(14,14))
for i in range(len(images)):
    plt.subplot(1,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
plt.tight_layout()
plt.show()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/216f6107-66c1-4a89-a0b7-644a2c8ed55f/image.png" alt=""></p>
<h4 id="2-gaussian-filtering">2. Gaussian Filtering</h4>
<p>Gaussian Filter는 Gaussian 함수를 이용한 값으로 이루어진 커널 사용
cv2.GaussianBlur(img,ksize,sigmaX)
ksize는 width,height가 다를 수 있지만 양수의 홀수이어야 함</p>
<pre><code class="language-python"># 2. Gaussian Filtering
import cv2
import numpy as np

img = cv2.imread(&#39;emoji1.png&#39;)
b,g,r = cv2.split(img)
img = cv2.merge([r,g,b])

img_noise = img.copy()
img_noise = np.clip((img/255 + np.random.normal(
    scale = 0.1, size = img.shape)) * 255, 0, 255).astype(&#39;uint8&#39;)
img_gaussian = cv2.GaussianBlur(img_noise,(7,7),0)

images = [img_noise,img_gaussian]
titles = [&#39;White Noise&#39;,&#39;Gaussian Blur(7X7)&#39;]

plt.figure(figsize=(14,14))
for i in range(len(images)):
    plt.subplot(1,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
plt.tight_layout()
plt.show()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/f7e428f4-91d0-497c-89e5-cf521b0d805d/image.png" alt=""></p>
<h4 id="3-median-filtering">3. Median Filtering</h4>
<p>커널내의 값들을 정렬한 후 중간값을 선택하여 적용
cv2.medianBlur(src,ksize)
ksize는 1보다 큰 홀수(3,5 등)</p>
<pre><code class="language-python"># 3. Median Filtering
import cv2
import numpy as np

img = cv2.imread(&#39;emoji1.png&#39;)
b,g,r = cv2.split(img)
img = cv2.merge([r,g,b])

img_pepper = img.copy()
n = 10000
np.random.seed(20)
idx1 = np.random.randint(img_pepper.shape[0],size = n)
idx2 = np.random.randint(img_pepper.shape[1],size = n)
img_pepper[idx1,idx2] = 0
img_median = cv2.medianBlur(img_pepper,9)

images = [img_pepper,img_median]
titles = [&#39;Pepper Noise&#39;,&#39;Median Blur(9X9)&#39;]

plt.figure(figsize=(14,14))
for i in range(len(images)):
    plt.subplot(1,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
plt.tight_layout()
plt.show()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/bb861229-e02f-4c07-a1ab-61a22b4a5ee0/image.png" alt=""></p>
<h4 id="4-bilateral-filtering">4. Bilateral Filtering</h4>
<p>지금까지의 Blur처리와 달리 경계선을 유지하며 Gaussian Blur처리
Gaussian 필터를 적용하고 또 하나의 Gaussian 필터를 주변 픽셀까지 고려하여 적용하는 방식
cv2.bilateralBlur(src,d,sigmaColor,sigmaSpace)
src : 8비트, 1 or 3 채널 이미지
d : 필터링시 고려할 주변 픽셀 지름 (커널 사이즈)
sigmaColor : 색을 고려할 공간. 숫자가 크면 멀리 있는 색도 고려
sigmaSpace : 숫자가 크면 멀리 있는 픽셀도 고려</p>
<pre><code class="language-python"># 4. Bilateral Filtering
import cv2
import numpy as np

img = cv2.imread(&#39;emoji1.png&#39;)
b,g,r = cv2.split(img)
img = cv2.merge([r,g,b])

img_noise = img.copy()
img_noise = np.clip((img/255 + np.random.normal(
    scale = 0.1, size = img.shape)) * 255, 0, 255).astype(&#39;uint8&#39;)
img_bilateral = cv2.bilateralFilter(img_noise,9,75,75)

images = [img_noise,img_bilateral]
titles = [&#39;White Noise&#39;,&#39;Bilateral Filtering(9X9)&#39;]

plt.figure(figsize=(14,14))
for i in range(len(images)):
    plt.subplot(1,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
plt.tight_layout()
plt.show()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/e8df3519-43f8-40e7-b09c-c0c38d4be867/image.png" alt=""></p>
<h4 id="종합">종합</h4>
<pre><code class="language-python">import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread(&#39;squirrel1.jpg&#39;)
# pyplot을 위해 BGR -&gt; RGB 변환
b,g,r = cv2.split(img)
img = cv2.merge([r,g,b])

# 1. Averaging
dst1 = cv2.blur(img,(7,7))
# 2. Gaussian Blur
dst2 = cv2.GaussianBlur(img,(5,5),0)
# 3. Median Blur
dst3 = cv2.medianBlur(img,9)
# 4. Bilateral Filtering
dst4 = cv2.bilateralFilter(img,9,75,75)

images = [img,dst1,dst2,dst3,dst4]
titles = [&#39;Original&#39;,&#39;Blur(7X7)&#39;,&#39;Gaussian Blur(5X5)&#39;,&#39;Median Blur&#39;,&#39;Bilateral&#39;]

plt.figure(figsize=(8,8))
for i in range(5):
    plt.subplot(3,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
plt.tight_layout()
plt.show()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/80279d24-3e57-4ba9-884e-05020fe15358/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenCV 9.이미지 변형]]></title>
            <link>https://velog.io/@real_jun9u/OpenCV-9.%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B3%80%ED%98%95</link>
            <guid>https://velog.io/@real_jun9u/OpenCV-9.%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B3%80%ED%98%95</guid>
            <pubDate>Sat, 15 Jan 2022 09:38:49 GMT</pubDate>
            <description><![CDATA[<h3 id="scailing">Scailing</h3>
<pre><code class="language-python">cv2.resize(src, dsize, [,dst [, fx[, fy [,interpolation]]]])</code></pre>
<ol>
<li>src : 입력 이미지</li>
<li>dsize : 출력 이미지 크기</li>
<li>fx : 가로 방향 배율</li>
<li>fy : 세로 방향 배율</li>
<li>interpolation : 이미지 크기 조정 시 누락되거나 축소되는 픽셀 값 결정 방법<blockquote>
<ol>
<li>cv2.INTER_NEAREST</li>
<li>cv2.INTER_LINEAR</li>
<li>cv2.INTER_CUBIC</li>
<li>cv2.INTER_AREA</li>
<li>cv2.INTER_LANCZOS4</li>
<li>cv2.INTER_LINEAR_EXACT</li>
<li>cv2.INTER_MAX</li>
<li>cv2.WARP_FILL_OUTLIERS</li>
<li>cv2.WARP_INVERSE_MAP
축소는 INTER_AREA, 확대는 INTER_CUBIC,INTER_LINEAR 사용</li>
</ol>
</blockquote>
</li>
</ol>
<pre><code class="language-python">import cv2
import numpy as np

img = cv2.imread(&#39;emoji1.png&#39;)
h,w = img.shape[:2]

shrink = cv2.resize(img,None,fx=0.5,fy=0.5,interpolation=cv2.INTER_AREA)
zoom1 = cv2.resize(img,(w*2,h*2),interpolation=cv2.INTER_CUBIC)
zoom2 = cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)

cv2.imshow(&#39;Original&#39;,img)
cv2.imshow(&#39;Shrink&#39;,shrink)
cv2.imshow(&#39;Zoom1&#39;,zoom1)
cv2.imshow(&#39;Zoom2&#39;,zoom2)

cv2.waitKey(0)
cv2.destroyAllWindows()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/2b1a53a1-4537-4eb5-9a6f-9c73ea3b227f/image.png" alt=""></p>
<h3 id="translation">Translation</h3>
<pre><code class="language-python">cv2.warpAffine(src,M,dsize)
# M - 변환 행렬</code></pre>
<pre><code class="language-python">import cv2
import numpy as np

img = cv2.imread(&#39;emoji1.png&#39;)
rows,columns = img.shape[:2]

M = np.float32([[1,0,100],[0,1,200]])
dst = cv2.warpAffine(img,M,(columns,rows))

cv2.imshow(&#39;Original&#39;,img)
cv2.imshow(&#39;Translation&#39;,dst)

cv2.waitKey(0)
cv2.destroyAllWindows()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/1bfd22f0-e9ee-445b-a9af-d0ad8c573ff7/image.png" alt=""></p>
<h3 id="rotation">Rotation</h3>
<pre><code class="language-python">cv2.getRotationMatrix2D(center,angle,scale) -&gt; M</code></pre>
<ol>
<li>center : 이미지의 중심 좌표</li>
<li>angle : 회전 좌표(반시계 방향)</li>
<li>scale : 스케일<pre><code class="language-python">import cv2
import numpy as np
</code></pre>
</li>
</ol>
<p>img = cv2.imread(&#39;emoji1.png&#39;)
rows,columns = img.shape[:2]</p>
<p>M = cv2.getRotationMatrix2D((columns/2,rows/2),90,0.5)
dst = cv2.warpAffine(img,M,(columns,rows))</p>
<p>cv2.imshow(&#39;Original&#39;,img)
cv2.imshow(&#39;Rotation&#39;,dst)</p>
<p>cv2.waitKey(0)
cv2.destroyAllWindows()</p>
<pre><code>![](https://images.velog.io/images/real_jun9u/post/15a56836-2b50-4bd4-9986-f3957640dacc/image.png)
### Affine Transformation
선의 평행성은 유지하며 변환. 이동, 확대, Scale, 반전이 포함
3개의 Match가 되는 점이 있으면 변환 행렬을 구할 수 있다.
```python
cv2.getAffineTransform(pts1,pts2) -&gt; M</code></pre><pre><code class="language-python">import cv2
import numpy as np

img = cv2.imread(&#39;emoji1.png&#39;)
rows,columns,channels = img.shape

pts1 = np.float32([[200,100],[400,100],[200,200]])
pts2 = np.float32([[200,200],[400,100],[200,300]])

cv2.circle(img,(200,100),10,(255,0,0),-1)
cv2.circle(img,(400,100),10,(0,255,0),-1)
cv2.circle(img,(200,200),10,(0,0,255),-1)

M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img,M,(columns,rows))

cv2.imshow(&#39;Original&#39;,img)
cv2.imshow(&#39;Affine Transform&#39;,dst)

cv2.waitKey(0)
cv2.destroyAllWindows()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/0a480cb4-5536-4ead-a161-f859d023164c/image.png" alt=""></p>
<h3 id="perspective-transform">Perspective Transform</h3>
<p>직선의 성질만 유지. 기차길이 평항하지만 원근변환을 거치면 만나는 것 처럼 보인다.</p>
<pre><code class="language-python">cv2.getPerspectiveTransform() -&gt; M
cv2.warpPerspective() -&gt; dst</code></pre>
<pre><code class="language-python">import cv2
import numpy as np
import matplotlib.pyplot as plt

pts1 = []
colors = [(255,0,0),(0,255,0),(0,0,255),(0,0,0)]

def onMouse(event,x,y,flags,param):
    global pts1
    if event == cv2.EVENT_LBUTTONDOWN:
        cv2.circle(param,(x,y),5,colors[len(pts1)],-1)
        pts1.append([x,y])
        cv2.imshow(&#39;Perspective Transform&#39;,param)
def WritePoints():    
    img = cv2.imread(&#39;train_road1.jpg&#39;)
    # [x,y] 좌표를 4개 작성
    # 좌상 -&gt; 좌하 -&gt; 우상 -&gt; 우하
    cv2.imshow(&#39;Perspective Transform&#39;,img)
    cv2.setMouseCallback(&#39;Perspective Transform&#39;,onMouse,img)
    while True:
        cv2.imshow(&#39;Perspective Transform&#39;,img)
        k = cv2.waitKey(0) &amp; 0xFF
        if k == 27:
            break
    cv2.destroyAllWindows()
    return img

img = WritePoints()
rows,columns = img.shape[:2]

pts1 = np.float32(pts1)
pts2 = np.float32([[20,20],[20,340],[620,20],[620,340]])

M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,M,(columns,rows))

cv2.imshow(&#39;Original&#39;,img)
cv2.imshow(&#39;Perspective Transform&#39;,dst)

cv2.waitKey(0)
cv2.destroyAllWindows()</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/32944d64-f837-4611-a5dc-9829c1542d70/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/파이썬] 18870번 - 좌표 압축]]></title>
            <link>https://velog.io/@real_jun9u/%EB%B0%B1%EC%A4%80%ED%8C%8C%EC%9D%B4%EC%8D%AC-18870%EB%B2%88-%EC%A2%8C%ED%91%9C-%EC%95%95%EC%B6%95</link>
            <guid>https://velog.io/@real_jun9u/%EB%B0%B1%EC%A4%80%ED%8C%8C%EC%9D%B4%EC%8D%AC-18870%EB%B2%88-%EC%A2%8C%ED%91%9C-%EC%95%95%EC%B6%95</guid>
            <pubDate>Tue, 11 Jan 2022 02:11:05 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-설명">문제 설명</h3>
<p><img src="https://images.velog.io/images/real_jun9u/post/f961da1d-acc6-4cb0-90db-cf5c51c6e208/image.png" alt=""></p>
<h3 id="풀이-전략">풀이 전략</h3>
<p>문제를 분석해보면 N개의 숫자가 주어지고 각 숫자에 대해 자기보다 작은 숫자의 수를 출력해야한다. N의 범위가 $1\leq N \leq 1,000,000$ 이고, 입력 숫자의 범위는 $-10^9 \leq X_i \leq 10^9$ 이다.
출력해야 하는 값은 자신보다 작은 값의 갯수이므로, 중복을 제거하고 정렬된 배열에서의 인덱스를 출력하면 된다. 여기서 그대로 출력 시 각 숫자에 대해 정렬된 배열속의 인덱스를 찾게 되면 매 번 배열을 순회하는 것과 마찬가지 이므로 시간이 초과된다. 이 때 정렬된 배열의 값과 인덱스를 딕셔너리 형태로 저장하면 출력 시에도 한번에 조회가 가능하므로 해결가능하다.</p>
<h3 id="코드">코드</h3>
<pre><code class="language-python">import sys
n = int(sys.stdin.readline().rstrip())
arr = list(map(int,sys.stdin.readline().rstrip().split()))
arr2 = list(sorted(set(arr))) # 중복 제거
numdict={arr2[i]: i for i in range(len(arr2))}
for i in range(n):
    print(numdict[arr[i]],end=&#39; &#39;)</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/cf5e1d61-af15-44ce-bf1a-ef937a47028f/image.png" alt=""></p>
<ul>
<li>참고 - 한 줄에 출력할 때 출력 방법을 아래로 하면 시간이 더 줄어든다.<pre><code class="language-python">print(*[numdict[i] for i in arr])</code></pre>
<img src="https://images.velog.io/images/real_jun9u/post/0f3acde9-8c50-41f0-a879-09f2d1389ade/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/파이썬] 2108 - 통계학]]></title>
            <link>https://velog.io/@real_jun9u/%EB%B0%B1%EC%A4%80%ED%8C%8C%EC%9D%B4%EC%8D%AC-2108-%ED%86%B5%EA%B3%84%ED%95%99</link>
            <guid>https://velog.io/@real_jun9u/%EB%B0%B1%EC%A4%80%ED%8C%8C%EC%9D%B4%EC%8D%AC-2108-%ED%86%B5%EA%B3%84%ED%95%99</guid>
            <pubDate>Tue, 11 Jan 2022 01:53:43 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-설명">문제 설명</h3>
<p><img src="https://images.velog.io/images/real_jun9u/post/bf989f4a-4297-4b96-8790-1fa969af3a6a/image.png" alt=""></p>
<h3 id="풀이-전략">풀이 전략</h3>
<p>문제에서 구해야하는 값 중 중앙값, 최빈값은 정렬을 해야만 구할 수 있는 값이므로 정렬을 해야하는데, 그 중 최빈값을 구하는 방법에 따라 두 가지로 구현하였다.</p>
<ol>
<li>계수 정렬을 이용하여 빈도 수를 같이 구하고, 게수 배열을 돌며 최빈값들을 저장하여 구하기</li>
<li>퀵 정렬(sort())를 이용하여 정렬하고, collections 모듈의 Counter 함수를 사용하여 최빈값 구하기</li>
</ol>
<p>2번 방법이 더 간단하지만 실행 결과를 보면 1번 방법이 메모리와 실행시간이 훨씬 효율적인 것을 볼 수 있다.</p>
<h3 id="코드">코드</h3>
<h4 id="1-계수-정렬">1. 계수 정렬</h4>
<pre><code class="language-python">import sys

arr=[]
counts=[]
# 입력 정수의 범위가 -4000 ~ 4000
# 파이썬 음수 인덱싱을 이용하여 8001크기의 배열 생성
countarr=[0] * 8001
for _ in range(int(input())):
    countarr[int(sys.stdin.readline().rstrip())] += 1
for i in range(-4000,4001):
    for _ in range(countarr[i]):
        arr.append(i)
print(round(sum(arr)/len(arr)))
print(arr[len(arr)//2])
# 최대 빈도 저장
maxfreq = max(countarr)
while True:
    # index()메서드는 해당하는 값이 없으면 오류 출력
    # try except문을 통해 제어한다.
    try:
        # 최대 빈도를 가진 인덱스 저장
        idx = countarr.index(maxfreq)
        # 찾은 값은 제거
        countarr[idx] = 0
        # 인덱스가 4000을 넘으면 8001을 뺀 인덱스로 본다.
        if idx &gt; 4000:
            idx -= 8001
        counts.append(idx)
    except:
        break
counts.sort() # 저장한 최대 빈도 값들을 정렬
if len(counts) &gt; 1:
    print(counts[1])
else:
    print(counts[0])
print(max(arr)-min(arr))</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/5b22f0d2-ae0f-44de-820b-6443eaaae82b/image.png" alt=""></p>
<h4 id="2-counter-함수-사용">2. Counter 함수 사용</h4>
<pre><code class="language-python">import sys
from collections import Counter

arr=[]
for _ in range(int(input())):
    arr.append(int(sys.stdin.readline().rstrip()))
arr.sort()

print(round(sum(arr)/len(arr)))
print(arr[len(arr)//2])
# 빈도수가 많은 순서대로 2개 저장
count = Counter(arr).most_common(2)
if len(count) &gt; 1:
    # 최빈값이 2개이면 작은 것 출력
    if count[0][1] == count[1][1]:
        print(count[1][0])
    else:
        print(count[0][0])
else:
    print(count[0][0])
print(max(arr)-min(arr))</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/0a785e7c-33ce-450c-9052-e851f9f6bb53/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/파이썬] 10989 - 수 정렬하기 3]]></title>
            <link>https://velog.io/@real_jun9u/%EB%B0%B1%EC%A4%80%ED%8C%8C%EC%9D%B4%EC%8D%AC-10989-%EC%88%98-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-3</link>
            <guid>https://velog.io/@real_jun9u/%EB%B0%B1%EC%A4%80%ED%8C%8C%EC%9D%B4%EC%8D%AC-10989-%EC%88%98-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-3</guid>
            <pubDate>Tue, 11 Jan 2022 01:33:59 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-설명">문제 설명</h3>
<p><img src="https://images.velog.io/images/real_jun9u/post/58fe3e47-4b59-4320-88d8-e0ef52cd9849/image.png" alt=""></p>
<h3 id="풀이-전략">풀이 전략</h3>
<p>N의 범위가 $1\leq N\leq 10,000,000$ 으로 $O(NlogN)$의 알고리즘으로도 시간 초과가 발생한다. 입력으로 주어지는 자연수의 범위가 $1\leq K\leq 10,000$ 이므로 $O(N+K)$의 알고리즘인 계수 정렬을 이용하면 해결할 수 있다. 계수 정렬은 각 숫자를 배열의 인덱스로 가지고, 배열의 내용은 해당 숫자의 갯수를 배열을 생성해 정렬하는 방법이다.</p>
<h3 id="코드">코드</h3>
<pre><code class="language-python">import sys
arr = [0] * 10001
n = int(sys.stdin.readline().rstrip())
for _ in range(n):
    arr[int(sys.stdin.readline().rstrip())] += 1
for i in range(1,len(arr)):
    for _ in range(arr[i]):
        print(i)</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/1f847e16-a833-4c10-bfb6-a386270d773b/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준/파이썬] 2751번 - 수 정렬하기 2]]></title>
            <link>https://velog.io/@real_jun9u/%EB%B0%B1%EC%A4%80%ED%8C%8C%EC%9D%B4%EC%8D%AC-2751%EB%B2%88-%EC%88%98-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-2</link>
            <guid>https://velog.io/@real_jun9u/%EB%B0%B1%EC%A4%80%ED%8C%8C%EC%9D%B4%EC%8D%AC-2751%EB%B2%88-%EC%88%98-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-2</guid>
            <pubDate>Tue, 11 Jan 2022 01:26:29 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-설명">문제 설명</h3>
<p><img src="https://images.velog.io/images/real_jun9u/post/e90e3cfc-71c8-4826-b19b-ab7d09234abe/image.png" alt=""></p>
<h3 id="풀이-전략">풀이 전략</h3>
<p>N의 범위가 $1\leq N\leq1,000,000$이므로 $O(NlogN)$의 복잡도를 가진 정렬을 이용한다. 파이썬 내장함수 $sort(), sorted()$가 퀵 정렬로 구현되어 $O(NlogN)$을 가지므로 사용하고, 입력이 N번 들어오므로 $input()$함수 대신 $sys.stdin.readline()$을 이용한다.</p>
<h3 id="코드">코드</h3>
<pre><code class="language-python">import sys
n = int(input())
arr=[]
for _ in range(n):
    arr.append(int(sys.stdin.readline().rstrip()))
arr.sort()
for i in arr:
    print(i)</code></pre>
<p><img src="https://images.velog.io/images/real_jun9u/post/c7a1ec88-9521-48b1-b66c-c42caaa76c54/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>