File size: 9,211 Bytes
bbe1ed5
f586132
c98abc8
 
f586132
 
 
f5f4f69
f586132
f8f00d1
 
 
 
e1371e7
 
f8f00d1
11301ec
 
f8f00d1
e1371e7
f8f00d1
 
 
f586132
03db935
 
 
f8f00d1
 
 
fc729f5
f8f00d1
03db935
f8f00d1
 
 
 
 
03db935
f586132
03db935
 
 
 
 
 
1a1812a
03db935
 
 
 
 
 
 
 
 
f586132
 
 
f8f00d1
a2ec5a9
03db935
 
 
 
 
 
a2ec5a9
fc729f5
 
 
 
 
 
 
03db935
a2ec5a9
03db935
f586132
6b14869
03db935
 
 
 
 
 
 
 
 
 
 
6b14869
 
03db935
 
 
 
 
 
 
 
 
 
 
 
 
f8f00d1
03db935
 
 
 
f8f00d1
03db935
f8f00d1
03db935
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1a1812a
f586132
03db935
 
 
 
 
fc729f5
 
 
 
03db935
 
 
 
 
f586132
f8f00d1
 
 
bbe1ed5
e1f10a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f586132
e1f10a7
 
f586132
 
 
 
d34cf4e
e1f10a7
f586132
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ae4d776
f586132
ae4d776
 
 
f586132
 
 
 
 
 
 
03db935
 
 
 
8b878c9
f586132
03db935
 
 
e1371e7
a3956de
f586132
11301ec
8b878c9
a2ed5c3
 
 
 
 
 
11301ec
 
 
 
 
 
 
 
 
 
 
a3956de
11301ec
 
 
f5f4f69
11301ec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
import streamlit as st
import streamlit.components.v1 as components
import cv2
import numpy as np
from PIL import Image, ExifTags

# κ°€μž₯ λ¨Όμ € set_page_config() 호좜
st.set_page_config(page_title="λ”₯페이크 사전 λ°©μ§€ ν•„ν„°(ν…ŒμŠ€νŠΈ)", layout="wide")

# λ‚˜λ¨Έμ§€ Streamlit μ½”λ“œ
st.title("λ”₯페이크 사전 λ°©μ§€ ν•„ν„°(ν…ŒμŠ€νŠΈ)")
st.markdown("")
st.markdown("<span style='font-size: 18px;'>μ•ˆλ…•ν•˜μ„Έμš”! μ €ν¬λŠ” λ”₯νŽ˜μ΄ν¬λ‘œλΆ€ν„° μ—¬λŸ¬λΆ„μ˜ 사진을 λ³΄ν˜Έν•˜λŠ” μ†”λ£¨μ…˜μ„ κ°œλ°œν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.</span>", unsafe_allow_html=True)
st.markdown("<span style='font-size: 18px;'>μ €ν¬μ˜ λͺ©ν‘œλŠ” μ˜¨λΌμΈμ— κ²Œμ‹œλœ 개인의 사진이 μ•…μ„± λ”₯페이크 μ˜μƒμ— μ‚¬μš©λ˜μ§€ μ•Šλ„λ‘ ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 정식 둠칭에 μ•žμ„œ, μ—¬λŸ¬λΆ„μ˜ μ˜κ²¬μ„ λ“£κΈ° μœ„ν•΄ κ°„λ‹¨ν•œ ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.</span>", unsafe_allow_html=True)
st.markdown("<span style='font-size: 18px;'>졜근 SNS에 μ—…λ‘œλ“œλœ 이미지가 λ”₯νŽ˜μ΄ν¬μ— μ•…μš©λ˜λŠ” 사둀가 맀일 보고되고 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ 해결책을 κ°•κ΅¬ν•˜κΈ° μœ„ν•΄, μ—¬λŸ¬λΆ„μ˜ μ†Œμ€‘ν•œ 의견이 ν•„μš”ν•©λ‹ˆλ‹€.</span>", unsafe_allow_html=True)
st.markdown("")
st.markdown("<span style='font-size: 18px;'>μ§„ν–‰ κ³Όμ • 1. μ‚¬λžŒ 이미지λ₯Ό μ—…λ‘œλ“œν•˜λ©΄, 사전 λ°©μ§€ ν•„ν„°κ°€ 적용된 이미지λ₯Ό λ³΄μ—¬λ“œλ¦½λ‹ˆλ‹€.</span>", unsafe_allow_html=True)
st.markdown("<span style='font-size: 18px;'>μ§„ν–‰ κ³Όμ • 2. λ”₯페이크 μ‹€ν–‰ λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄, λ”₯페이크 κ²°κ³Όλ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.</span>", unsafe_allow_html=True)
st.markdown("<span style='font-size: 18px;'>μ—¬λŸ¬λΆ„μ˜ 참여에 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€!</span>", unsafe_allow_html=True)
st.markdown("<span style='font-size: 14px;'> *사전 λ°©μ§€ ν•„ν„°λž€: 사진에 λ―Έμ„Έν•œ λ³€ν™”λ₯Ό μ£Όμ–΄ λ”₯페이크 λͺ¨λΈμ— ν•™μŠ΅λ˜μ§€ λͺ»ν•˜λ„둝 λ°©ν•΄ν•˜λŠ” ν•„ν„°.</span>", unsafe_allow_html=True)
st.markdown(
    """
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
    <style>
    /* 곡톡 μŠ€νƒ€μΌ */
    .stFileUploader label,
    .stRadio label,
    .stRadio div,
    .custom-caption-1,
    .custom-caption-2,
    .custom-caption-3,
    .button-container,
    .stButton button,
    .survey,
    .survey-1,
    .survey-2,
    .a-tag,
    a {
        transition: all 0.3s ease;
    }
    .stFileUploader label {
        font-size: 20px;
        font-weight: 500;
        color: #1f77b4;
    }
    .stRadio label {
        font-size: 20px;
        font-weight: 500;
        color: #1f77b4;
    }
    .stRadio div {
        display: flex;
        gap: 20px;
    }
    .custom-caption-1 {
        font-size: 36px;
        font-weight: bold;
        text-align: center;
        margin-top: 10px;
        padding: 0 0 200px 0;
    }
    .custom-caption-2 {
        font-size: 36px;
        font-weight: bold;
        text-align: center;
        margin-top: 10px;
        padding: 0 0 30px 0;
    }
    .custom-caption-3 {
        font-size: 30px;
        # font-weight: bold;
        text-align: center;
        margin-top: 10px;
        padding: 0 0 30px 0;
    }
    .button-container {
        text-align: center;
        margin-top: 30px;
    }
    .stButton button {
        width: 50%;
        font-size: 25px;
        padding: 10px 20px;
        background-color: #FFFFFF;
        font-weight: bold;
        color: black;
        opacity: 0.8;
        border: 3px solid black;
        border-radius: 5px;
        cursor: pointer;
        margin: 0 auto 50px auto;
        display: block;
    }
    .stButton button:hover {
        background-color: #FFFFFF;
        border: 3px solid #FF0080;
        color: #FF0080;
        opacity: 1;
    }
    .survey {
        text-align: center;
        margin-top: 10px
    }
    .survey-1 {
        font-size: 25px;
        text-align: center;
        margin-top: 10px
        font-weight: bold;
    }
    .survey-2 {
        text-align: center;
        margin-top: 10px
        font-weight: bold;
        padding 0 auto 50px auto
    }
    .a-tag {
        color: #FF0080;
        text-decoration: none;
    }
    a:hover {
        color: #FF0080;
        text-decoration: none;
    }
    
    /* 슀마트폰 ν™”λ©΄ μŠ€νƒ€μΌ */
    @media only screen and (max-width: 600px) {
        .stFileUploader label,
        .stRadio label,
        .stButton button,
        .survey-1 {
            font-size: 16px;
        }
        .custom-caption-1,
        .custom-caption-2 {
            font-size: 24px;
            padding: 0 0 20px 0;
        }
        .custom-caption-3 {
            font-size: 20px;
            padding: 0 0 20px 0;
        }
        .stButton button {
            width: 100%;
            font-size: 18px;
        }
    }
    </style>
    """,
    unsafe_allow_html=True,
)

def change_hair_to_blonde(image):
    # Convert to OpenCV format
    image = np.array(image)
    # Convert the image to HSV color space
    hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)

    # Define the range for hair color (dark colors)
    lower_hair = np.array([0, 0, 0])
    upper_hair = np.array([180, 255, 30])

    # Create a mask for hair
    mask = cv2.inRange(hsv, lower_hair, upper_hair)

    # Change hair color to blonde (light yellow)
    hsv[mask > 0] = (30, 255, 200)

    # Convert back to RGB color space
    image_blonde = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
    return image_blonde

def add_noise(image):
    # Convert to OpenCV format
    image_np = np.array(image)
    # Generate random noise
    noise = np.random.normal(0, 25, image_np.shape).astype(np.uint8)
    # Add noise to the image
    noisy_image = cv2.add(image_np, noise)
    return noisy_image

def correct_image_orientation(image):
    try:
        for orientation in ExifTags.TAGS.keys():
            if ExifTags.TAGS[orientation] == 'Orientation':
                break
        exif = image._getexif()
        if exif is not None:
            orientation = exif.get(orientation, 1)
            if orientation == 3:
                image = image.rotate(180, expand=True)
            elif orientation == 6:
                image = image.rotate(270, expand=True)
            elif orientation == 8:
                image = image.rotate(90, expand=True)
    except (AttributeError, KeyError, IndexError):
        pass
    return image

uploaded_file = st.file_uploader("이미지λ₯Ό μ—…λ‘œλ“œν•˜μ„Έμš”...", type=["jpg", "png", "jpeg"])

if uploaded_file is not None:
    image = Image.open(uploaded_file)
    image = correct_image_orientation(image)
    
    st.write("이미지 처리 쀑...")

    # Save the original image as a numpy array
    image_np = np.array(image)

    col1, col2 = st.columns(2)
    
    with col1:
        st.image(image, use_column_width=True)
        st.markdown('<div class="custom-caption-1">μ—…λ‘œλ“œν•œ 원본 이미지</div>', unsafe_allow_html=True)

    with col2:
        st.image(image, use_column_width=True)
        st.markdown('<div class="custom-caption-1">ν•„ν„°λ₯Ό μž…νžŒ 이미지</div>', unsafe_allow_html=True)
    
    st.markdown('<div class="custom-caption-1">ν•„ν„°λ₯Ό μž…νžŒ μ΄λ―Έμ§€λŠ” μœ‘μ•ˆμœΌλ‘œ λ΄€μ„λ•Œ, 큰 차이가 μ—†μŒ</div>', unsafe_allow_html=True)

    button_clicked = st.button("λ”₯페이크 μ μš©ν•˜κΈ°")
    
    col3, col4 = st.columns(2)
    
    if button_clicked:
        processed_image = change_hair_to_blonde(image)
        deepfake_image = add_noise(image)
    else:
        processed_image = None
        deepfake_image = None

    if processed_image is not None and deepfake_image is not None:
        with col3:
            st.image(processed_image, use_column_width=True)
            st.markdown('<div class="custom-caption-2">원본 μ΄λ―Έμ§€λ‘œ λ”₯페이크λ₯Ό μ œμž‘ν•œ 경우</div>', unsafe_allow_html=True)
            st.markdown('<div class="custom-caption-3">이해λ₯Ό 돕기 μœ„ν•΄ 사진에 λ…Έλž€μƒ‰μ„ μž…νžˆλŠ” λ”₯페이크 μ•Œκ³ λ¦¬μ¦˜ 적용. 원본 μ΄λ―Έμ§€λŠ” λ”₯페이크 μ•Œκ³ λ¦¬μ¦˜μ˜ 영ν–₯을 λ°›μŒ.</div>', unsafe_allow_html=True)
        
        with col4:
            st.image(deepfake_image, use_column_width=True)
            st.markdown('<div class="custom-caption-2">λ°©μ§€ ν•„ν„° μ΄λ―Έμ§€λ‘œ λ”₯페이크λ₯Ό μ œμž‘ν•œ 경우</div>', unsafe_allow_html=True)
            st.markdown('<div class="custom-caption-3">λ°©μ§€ ν•„ν„°λ₯Ό μž…νžŒ μ΄λ―Έμ§€λŠ” λ”₯페이크의 영ν–₯을 λ°›μ§€ μ•Šκ³  μ•Œμ•„λ³΄κΈ° νž˜λ“  사진을 좜λ ₯ν•¨μœΌλ‘œμ¨ 이미지λ₯Ό λ³΄ν˜Έν•¨.</div>', unsafe_allow_html=True)
        
        st.markdown('<p class="survey"> μœ μ‚¬ν•œ μ„œλΉ„μŠ€λ₯Ό μ‚¬μš©ν•΄ λ³΄μ…¨κ±°λ‚˜, 저희 기술적 원리에 관심이 μžˆμœΌμ‹  λΆ„λ“€κ»˜μ„  μ•„λž˜μ˜ κ°„λ‹¨ν•œ 인터뷰에 μ°Έμ—¬ν•΄ μ£Όμ‹œλ©΄ μ§„μ‹¬μœΌλ‘œ κ°μ‚¬λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.</p>', unsafe_allow_html=True)
        st.markdown('<p class="survey-1"><a href="https://docs.google.com/forms/d/e/1FAIpQLSdzRtuvQyp3CQDhlxEag40v2yDM7u9NYpJ2gv5kgwuNbo1gUA/viewform?usp=sf_link" target="_blank" class="a-tag">μΈν„°λ·°λ‘œ λ”₯νŽ˜μ΄ν¬μ— λ§žμ„œκΈ°!!</a></p>', unsafe_allow_html=True)
        st.markdown('<p class="survey-2">μ„œλΉ„μŠ€λ₯Ό μ΄μš©ν•΄ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€! 쒋은 ν•˜λ£¨ λ³΄λ‚΄μ„Έμš”!</p>', unsafe_allow_html=True)