- •Об авторе
- •О научных редакторах
- •Благодарности
- •От издательства
- •Введение
- •Для кого эта книга?
- •Почему Python?
- •План книги
- •Версия Python, платформа и IDE
- •Установка Python
- •Запуск Python
- •Использование виртуальной среды
- •Вперед!
- •Глава 1. Спасение моряков с помощью теоремы Байеса
- •Теорема Байеса
- •Проект #1. Поиск и спасение
- •Стратегия
- •Установка библиотек Python
- •Код для теоремы Байеса
- •Время сыграть
- •Итоги
- •Дополнительная литература
- •Усложняем проект. Более грамотный поиск
- •Усложняем проект. Поиск лучшей стратегии с помощью MCS
- •Усложняем проект. Вычисление вероятности обнаружения
- •Глава 2. Установление авторства с помощью стилометрии
- •Проект #2: «Собака Баскервилей», «Война миров» и «Затерянный мир»
- •Стратегия
- •Установка NLTK
- •Корпусы текстов
- •Код стилометрии
- •Итоги
- •Дополнительная литература
- •Практический проект: охота на собаку Баскервилей с помощью распределения
- •Практический проект: тепловая карта пунктуации
- •Усложняем проект: фиксирование частотности
- •Глава 3. Суммаризация текста с помощью обработки естественного языка
- •Стратегия
- •Веб-скрапинг
- •Код для «У меня есть мечта»
- •Установка gensim
- •Код для суммаризации речи «Заправляйте свою кровать»
- •Проект #5. Суммаризация речи с помощью облака слов
- •Модули Word Cloud и PIL
- •Код для создания облака слов
- •Итоги
- •Дополнительная литература
- •Усложняем проект: ночные игры
- •Усложняем проект: суммаризация суммаризаций
- •Глава 4. Отправка суперсекретных сообщений с помощью книжного шифра
- •Одноразовый блокнот
- •Шифр «Ребекка»
- •Проект #6. Цифровой ключ к «Ребекке»
- •Стратегия
- •Код для шифрования
- •Отправка сообщений
- •Итоги
- •Дополнительная литература
- •Глава 5. Поиск Плутона
- •Проект #7. Воссоздание блинк-компаратора
- •Стратегия
- •Данные
- •Код блинк-компаратора
- •Использование блинк-компаратора
- •Проект #8. Обнаружение астрономических транзиентов путем дифференцирования изображений
- •Стратегия
- •Код для детектора транзиентов
- •Использование детектора транзиентов
- •Итоги
- •Дополнительная литература
- •Практический проект: представление орбитальной траектории
- •Практический проект: найди отличия
- •Усложняем проект: сосчитаем звезды
- •Глава 6. Победа в лунной гонке с помощью «Аполлона-8»
- •Цель миссии «Аполлон-8»
- •Траектория свободного возврата
- •Задача трех тел
- •Проект #9. На Луну с «Аполлоном-8»!
- •Использование модуля turtle
- •Стратегия
- •Код программы для расчета свободного возврата «Аполлона-8»
- •Выполнение симуляции
- •Итоги
- •Дополнительная литература
- •Практический проект: симуляция шаблона поисков
- •Практический проект: запусти меня!
- •Практический проект: останови меня!
- •Усложняем проект: симуляция в истинном масштабе
- •Усложняем проект: реальный «Аполлон-8»
- •Глава 7. Выбор мест высадки на Марсе
- •Посадка на Марс
- •Карта MOLA
- •Проект #10. Выбор посадочных мест на Марсе
- •Стратегия
- •Код для выбора мест посадки
- •Результаты
- •Итоги
- •Дополнительная литература
- •Практический проект: убедимся, что рисунки становятся частью изображения
- •Практический проект: визуализация профиля высот
- •Практический проект: отображение в 3D
- •Практический проект: совмещение карт
- •Усложняем проект: три в одном
- •Усложняем проект: перенос прямоугольников
- •Глава 8. Обнаружение далеких экзопланет
- •Транзитная фотометрия
- •Проект #11. Симуляция транзита экзопланеты
- •Стратегия
- •Код для транзита
- •Эксперименты с транзитной фотометрией
- •Проект #12. Получение изображений экзопланет
- •Стратегия
- •Код для пикселизатора
- •Итоги
- •Дополнительная литература
- •Практический проект: обнаружение инопланетных мегаструктур
- •Практический проект: обнаружение транзита астероидов
- •Практический проект: добавление эффекта потемнения к краю
- •Практический проект: обнаружение пятен на звездах
- •Практический проект: обнаружение инопланетной армады
- •Практический проект: обнаружение планеты с луной
- •Практический проект: измерение продолжительности экзопланетного дня
- •Усложняем проект: генерация динамической кривой блеска
- •Глава 9. Как различить своих и чужих
- •Обнаружение лиц на фотографиях
- •Проект #13. Программирование робота-часового
- •Стратегия
- •Результаты
- •Обнаружение лиц в видеопотоке
- •Итоги
- •Дополнительная литература
- •Практический проект: размытие лиц
- •Усложняем проект: обнаружение кошачьих мордочек
- •Глава 10. Ограничение доступа по принципу распознавания лиц
- •Распознавание лиц с помощью LBPH
- •Схема распознавания лиц
- •Извлечение гистограмм локальных бинарных шаблонов
- •Проект #14. Ограничение доступа к инопланетному артефакту
- •Стратегия
- •Поддержка модулей и файлов
- •Код для захвата видео
- •Код для обучения алгоритма распознавания лиц
- •Код для прогнозирования лиц
- •Результаты
- •Итоги
- •Дополнительная литература
- •Усложняем проект: добавление пароля и видеозахвата
- •Усложняем проект: похожие лица и близнецы
- •Усложняем проект: машина времени
- •Глава 11. Создание интерактивной карты побега от зомби
- •Проект #15. Визуализация плотности населения с помощью хороплетной карты
- •Стратегия
- •Библиотека анализа данных
- •Библиотеки bokeh и holoviews
- •Установка pandas, bokeh и holoviews
- •Работа с данными по уровню безработицы и плотности населения в округах и штатах
- •Разбираем код holoviews
- •Код для отрисовки хороплетной карты
- •Планирование маршрута
- •Итоги
- •Дополнительная литература
- •Усложняем проект: отображение на карте изменения численности населения США
- •Глава 12. Находимся ли мы в компьютерной симуляции?
- •Проект #16. Жизнь, Вселенная и пруд черепахи Йертл
- •Код симуляции пруда
- •Следствия симуляции пруда
- •Измерение затрат на пересечение строк или столбцов сетки
- •Результаты
- •Стратегия
- •Итоги
- •Дополнительная литература
- •Дополнение
- •Усложняем проект: поиск безопасного места в космосе
- •Усложняем проект: а вот и Солнце
- •Усложняем проект: взгляд глазами собаки
- •Усложняем проект: кастомизированный поиск слов
- •Усложняем проект: что за сложную паутину мы плетем
- •Усложняем проект: идем вещать с горы
- •Решения для практических проектов
- •Глава 2. Определение авторства с помощью стилометрии
- •Охота на собаку Баскервилей с помощью распределения
- •Тепловая карта пунктуации
- •Глава 4. Отправка суперсекретных сообщений с помощью книжного шифра
- •Составление графика символов
- •Отправка секретов шифром времен Второй мировой войны
- •Глава 5. Поиск Плутона
- •Представление орбитальной траектории
- •Глава 6. Победа в лунной гонке с помощью «Аполлона-8»
- •Симуляция шаблона поисков
- •Заведи меня!
- •Останови меня!
- •Глава 7. Выбор мест высадки на Марсе
- •Убеждаемся, что рисунки становятся частью изображения
- •Визуализация профиля высоты
- •Отображение в 3D
- •Совмещение карт
- •Глава 8. Обнаружение далеких экзопланет
- •Обнаружение инопланетных мегаструктур
- •Обнаружение транзита астероидов
- •Добавление эффекта потемнения к краю
- •Обнаружение инопланетной армады
- •Обнаружение планеты с луной
- •Измерение продолжительности экзопланетного дня
- •Глава 9. Как различить своих и чужих
- •Размытие лиц
- •Глава 10. Ограничение доступа по принципу распознавания лиц
- •Усложняем проект: добавление пароля и видеозахвата
368 Решения для практических проектов
ship.shapesize(0.2) ship.color('red') # цвет траектории ship.getscreen().tracer(1, 0) ship.setheading(90) gravsys.sim_loop()
if __name__=='__main__': main()
Глава 7. Выбор мест высадки на Марсе
Убеждаемся, что рисунки становятся частью изображения
practice_confirm_drawing_part_of_image.py
"""Убеждаемся, что рисунки становятся частью изображения в OpenCV.""" import numpy as np
import cv2 as cv
IMG = cv.imread('mola_1024x501.png', cv.IMREAD_GRAYSCALE)
ul_x, ul_y = 0, 167 lr_x, lr_y = 32, 183
rect_img = IMG[ul_y : lr_y, ul_x : lr_x]
def run_stats(image):
"""Вычисляем статистики для массива numpy, полученного из изображения.""" print('mean = {}'.format(np.mean(image)))
print('std = {}'.format(np.std(image))) print('ptp = {}'.format(np.ptp(image))) print()
cv.imshow('img', IMG) cv.waitKey(1000)
#Статистики без рисунка на экране: print("No drawing") run_stats(rect_img)
#Статистики для прямоугольника с белой рамкой: print("White outlined rectangle")
cv.rectangle(IMG, (ul_x, ul_y), (lr_x, lr_y), (255, 0, 0), 1) run_stats(rect_img)
#Статистики для прямоугольника, закрашенного белым: print("White-filled rectangle")
cv.rectangle(IMG, (ul_x, ul_y), (lr_x, lr_y), (255, 0, 0), -1) run_stats(rect_img)
Визуализация профиля высоты
practice_profile_olympus.py
"""Профиль высоты горы Олимп с запада на восток.""" from PIL import Image, ImageDraw
from matplotlib import pyplot as plt
Глава 7. Выбор мест высадки на Марсе 369
#Загружаем изображение и получаем значения x и z вдоль горизонтального профиля, параллельного y координате.
y_coord = 202
im = Image.open('mola_1024x512_200mp.jpg').convert('L') width, height = im.size
x_vals = [x for x in range(width)]
z_vals = [im.getpixel((x, y_coord)) for x in x_vals]
#Рисуем профиль на изображении MOLA. draw = ImageDraw.Draw(im)
draw.line((0, y_coord, width, y_coord), fill=255, width=3) draw.text((100, 165), 'Olympus Mons', fill=255)
im.show()
#Строим графическое представление профиля.
fig, ax = plt.subplots(figsize=(9, 4)) axes = plt.gca()
axes.set_ylim(0, 400)
ax.plot(x_vals, z_vals, color='black') ax.set(xlabel='x-coordinate',
ylabel='Intensity (height)',
title="Mars Elevation Profile (y = 202)")
ratio = 0.15 # Уменьшаем вертикальное преувеличение в профиле рельефа. xleft, xright = ax.get_xlim()
ybase, ytop = ax.get_ylim() ax.set_aspect(abs((xright-xleft)/(ybase-ytop)) * ratio) plt.text(0, 310, 'WEST', fontsize=10)
plt.text(980, 310, 'EAST', fontsize=10) plt.text(100, 280, 'Olympus Mons', fontsize=8) ##ax.grid()
plt.show()
Отображение в 3D
practice_3d_plotting.py
"""Создаем графическое представление карты Марса MOLA в 3D. Реализация: Эрик Т. Мортенсон."""
import numpy as np import cv2 as cv
import matplotlib.pyplot as plt from mpl_toolkits import mplot3d
IMG_GRAY = cv.imread('mola_1024x512_200mp.jpg', cv.IMREAD_GRAYSCALE)
x = np.linspace(1023, 0, 1024) y = np.linspace(0, 511, 512)
X, Y = np.meshgrid(x, y)
Z = IMG_GRAY[0:512, 0:1024]
fig = plt.figure()
ax = plt.axes(projection='3d')
370 Решения для практических проектов
ax.contour3D(X, Y, Z, 150, cmap='gist_earth') # 150=количество контуров ax.auto_scale_xyz([1023, 0], [0, 511], [0, 500])
plt.show()
Совмещение карт
В этом практическом проекте используются две программы, practice_geo_map_ step_1of2.py и practice_geo_map_step_2of2.py, которые нужно выполнять по порядку.
practice_geo_map_step_1of2.py
practice_geo_map_step_1of2.py
"""Применяем заданный в значениях пикселей порог к полутоновому изображению и сохраняем результат в файл."""
import cv2 as cv
IMG_GEO = cv.imread('Mars_Global_Geology_Mariner9_1024.jpg', cv.IMREAD_GRAYSCALE)
cv.imshow('map', IMG_GEO) cv.waitKey(1000) img_copy = IMG_GEO.copy()
lower_limit = 170 # Минимальное полутоновое значение для вулканических отложений
upper_limit = 185 # Максимальное полутоновое значение для вулканических отложений
# Используем изображение 1024х512 for x in range(1024):
for y in range(512):
if lower_limit <= img_copy[y, x] <= upper_limit:
img_copy[y, x] = 1 # Устанавливаем на 255, чтобы визуализировать результат.
else:
img_copy[y, x] = 0
cv.imwrite('geo_thresh.jpg', img_copy) cv.imshow('thresh', img_copy) cv.waitKey(0)
practice_geo_map_step_2of2.py
practice_geo_map_step_2of2.py
"""Выбираем места высадки на Марсе, опираясь на гладкость поверхности и геологические особенности."""
import tkinter as tk
from PIL import Image, ImageTk import numpy as np
import cv2 as cv
Глава 7. Выбор мест высадки на Марсе 371
# Константы: пользовательский ввод:
IMG_GRAY = cv.imread('mola_1024x512_200mp.jpg', cv.IMREAD_GRAYSCALE) IMG_GEO = cv.imread('geo_thresh.jpg', cv.IMREAD_GRAYSCALE) IMG_COLOR = cv.imread('mola_color_1024x506.png')
RECT_WIDTH_KM = 670 # Ширина прямоугольного участка местности в километрах. RECT_HT_KM = 335 # Высота прямоугольного участка местности в километрах. MIN_ELEV_LIMIT = 60 # Значения интенсивности (0-255).
MAX_ELEV_LIMIT = 255
NUM_CANDIDATES = 20 # Количество предположительных мест высадки для отображения.
#----------------------------------------------------------------------------
#Константы: производные и фиксированные:
IMG_GRAY_GEO = IMG_GRAY * IMG_GEO IMG_HT, IMG_WIDTH = IMG_GRAY.shape
MARS_CIRCUM = 21344 # Окружность в километрах.
PIXELS_PER_KM = IMG_WIDTH / MARS_CIRCUM RECT_WIDTH = int(PIXELS_PER_KM * RECT_WIDTH_KM) RECT_HT = int(PIXELS_PER_KM * RECT_HT_KM) LAT_30_N = int(IMG_HT / 3)
LAT_30_S = LAT_30_N * 2
STEP_X = int(RECT_WIDTH / 2) # Деление на 4 дает больше прямоугольников. STEP_Y = int(RECT_HT / 2) # Деление на 4 дает больше прямоугольников.
#Создаем объекты экран tkinter и canvas для рисования.
screen = tk.Tk()
canvas = tk.Canvas(screen, width=IMG_WIDTH, height=IMG_HT + 130)
class Search():
"""Считываем изображение и определяем места посадки на основе вводных критериев."""
def __init__(self, name): self.name = name self.rect_coords = {} self.rect_means = {} self.rect_ptps = {} self.rect_stds = {} self.ptp_filtered = [] self.std_filtered = [] self.high_graded_rects = []
def run_rect_stats(self):
"""Определяем прямоугольные области поиска и вычисляем их внутренние статистики."""
ul_x, ul_y = 0, LAT_30_N
lr_x, lr_y = RECT_WIDTH, LAT_30_N + RECT_HT rect_num = 1
while True:
rect_img = IMG_GRAY_GEO[ul_y : lr_y, ul_x : lr_x] self.rect_coords[rect_num] = [ul_x, ul_y, lr_x, lr_y]
372 Решения для практических проектов
if MAX_ELEV_LIMIT >= np.mean(rect_img) >= MIN_ELEV_LIMIT: self.rect_means[rect_num] = np.mean(rect_img) self.rect_ptps[rect_num] = np.ptp(rect_img) self.rect_stds[rect_num] = np.std(rect_img)
rect_num += 1
# Смещаем прямоугольник. ul_x += STEP_X
lr_x = ul_x + RECT_WIDTH if if lr_x > IMG_WIDTH:
ul_x = 0
ul_y += STEP_Y lr_x = RECT_WIDTH lr_y += STEP_Y
if lr_y > LAT_30_S + STEP_Y: break
def draw_qc_rects(self):
"""Рисуем на изображении накладывающиеся прямоугольники поиска для проверки."""
img_copy = IMG_GRAY_GEO.copy()
rects_sorted = sorted(self.rect_coords.items(), key=lambda x: x[0]) print("\nRect Number and Corner Coordinates (ul_x, ul_y, lr_x,
lr_y):")
for k, v in rects_sorted:
print("rect: {}, coords: {}".format(k, v)) cv.rectangle(img_copy,
(self.rect_coords[k][0], self.rect_coords[k][1]), (self.rect_coords[k][2], self.rect_coords[k][3]), (255, 0, 0), 1)
cv.imshow('QC Rects {}'.format(self.name), img_copy) cv.waitKey(3000)
cv.destroyAllWindows()
def sort_stats(self):
"""Сортировка словарей по значениям и создание списков из N лучших ключей."""
ptp_sorted = (sorted(self.rect_ptps.items(), key=lambda x: x[1])) self.ptp_filtered = [x[0] for x in ptp_sorted[:NUM_CANDIDATES]] std_sorted = (sorted(self.rect_stds.items(), key=lambda x: x[1])) self.std_filtered = [x[0] for x in std_sorted[:NUM_CANDIDATES]]
#Создаем список прямоугольников, где отфильтрованные std и ptp совпадают.
for rect in self.std_filtered:
if rect in self.ptp_filtered: self.high_graded_rects.append(rect)
def draw_filtered_rects(self, image, filtered_rect_list):
"""Отрисовываем прямоугольники из списка на изображении и возвращаем его."""
img_copy = image.copy()
for k in filtered_rect_list: cv.rectangle(img_copy,
Глава 7. Выбор мест высадки на Марсе 373
(self.rect_coords[k][0], self.rect_coords[k][1]), (self.rect_coords[k][2], self.rect_coords[k][3]), (255, 0, 0), 1)
cv.putText(img_copy, str(k), (self.rect_coords[k][0] + 1, self.rect_coords[k][3]- 1),
cv.FONT_HERSHEY_PLAIN, 0.65, (255, 0, 0), 1)
# Рисуем границы широты.
cv.putText(img_copy, '30 N', (10, LAT_30_N - 7), cv.FONT_HERSHEY_PLAIN, 1, 255)
cv.line(img_copy, (0, LAT_30_N), (IMG_WIDTH, LAT_30_N), (255, 0, 0), 1)
cv.line(img_copy, (0, LAT_30_S), (IMG_WIDTH, LAT_30_S), (255, 0, 0), 1)
cv.putText(img_copy, '30 S', (10, LAT_30_S + 16), cv.FONT_HERSHEY_PLAIN, 1, 255)
return img_copy
def make_final_display(self):
"""Используем Tk для показа карты итоговых прямоугольников и вывода их статистик."""
screen.title('Sites by MOLA Gray STD & PTP {} Rect'.format(self.name))
# Рисуем высокоточные прямоугольники на цветной карте высот. img_color_rects = self.draw_filtered_rects(IMG_COLOR,
self.high_graded_rects)
#Преобразуем изображение из CV BGR в RGB для использования с помощью Tkinter.
img_converted = cv.cvtColor(img_color_rects, cv.COLOR_BGR2RGB) img_converted = ImageTk.PhotoImage(Image.fromarray(img_converted)) canvas.create_image(0, 0, image=img_converted, anchor=tk.NW)
#Добавляем в нижней части canvas статистики для каждого прямоугольника.
txt_x = 5
txt_y = IMG_HT + 15
for k in self.high_graded_rects:
canvas.create_text(txt_x, txt_y, anchor='w', font=None, text=
"rect={} mean elev={:.1f} std={:.2f} ptp={}"
.format(k, self.rect_means[k], self.rect_stds[k], self.rect_ptps[k]))
txt_y += 15
if txt_y >= int(canvas.cget('height')) - 10: txt_x += 300
txt_y = IMG_HT + 15 canvas.pack() screen.mainloop()
def main():
app = Search('670x335 km') app.run_rect_stats()