Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
484 changes: 242 additions & 242 deletions lab2.md

Large diffs are not rendered by default.

402 changes: 201 additions & 201 deletions lab3.md

Large diffs are not rendered by default.

166 changes: 83 additions & 83 deletions lab4.md

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions lab4/data_processor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import pandas as pd
from PIL import Image
from typing import List, Tuple


class DataProcessor:

@staticmethod
def create_dataframe_from_csv(csv_file: str) -> pd.DataFrame:
df = pd.read_csv(csv_file, encoding='utf-8')
df = df.rename(columns={
'Абсолютный путь': 'absolute_path',
'Относительный путь': 'relative_path'
})
return df

@staticmethod
def add_image_area_column(df: pd.DataFrame, area_ranges: List[Tuple[float, float, str]]) -> pd.DataFrame:
areas = []
area_categories = []

for _, row in df.iterrows():
try:
img = Image.open(row['absolute_path'])
width, height = img.size
area = width * height
category = DataProcessor._get_area_category(area, area_ranges)
areas.append(area)
area_categories.append(category)

except Exception:
areas.append(0)
area_categories.append("Error")

df['image_area'] = areas
df['area_category'] = area_categories
return df

@staticmethod
def _get_area_category(area: float, area_ranges: List[Tuple[float, float, str]]) -> str:
for min_val, max_val, category in area_ranges:
if min_val <= area < max_val:
return category

if area_ranges:
# Исправлено: убираем некорректное форматирование
last_max = area_ranges[-1][1]
if last_max == float('inf'):
# Если последний диапазон до бесконечности, возвращаем его название
return area_ranges[-1][2]
else:
# Иначе создаем категорию "больше чем"
return f">{last_max}"

return "Unknown"

@staticmethod
def create_default_area_ranges() -> List[Tuple[float, float, str]]:
return [
(0, 10000, "0-10k"),
(10000, 50000, "10k-50k"),
(50000, 100000, "50k-100k"),
(100000, 500000, "100k-500k"),
(500000, 1000000, "500k-1M"),
(1000000, float('inf'), ">1M")
]

@staticmethod
def parse_custom_ranges(range_str: str) -> List[Tuple[float, float, str]]:
if not range_str:
return DataProcessor.create_default_area_ranges()

ranges = []
parts = range_str.split(',')
for part in parts:
if ':' in part:
range_part, name = part.split(':', 1)
if '-' in range_part:
min_str, max_str = range_part.split('-', 1)
min_val = float(min_str.strip())

# Обработка бесконечности
if max_str.strip().lower() == 'inf':
max_val = float('inf')
else:
max_val = float(max_str.strip())

ranges.append((min_val, max_val, name.strip()))
return ranges

@staticmethod
def sort_by_area(df: pd.DataFrame, ascending: bool = True) -> pd.DataFrame:
return df.sort_values(by='image_area', ascending=ascending)

@staticmethod
def filter_by_area(df: pd.DataFrame, min_area: float = 0, max_area: float = float('inf')) -> pd.DataFrame:
return df[(df['image_area'] >= min_area) & (df['image_area'] <= max_area)]
73 changes: 73 additions & 0 deletions lab4/lab4_var4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import argparse
import sys
import matplotlib.pyplot as plt # Добавлен импорт plt
from typing import List, Tuple

from data_processor import DataProcessor
from visualizer import Visualizer


def parse_arguments():
parser = argparse.ArgumentParser(description='Анализ данных изображений')

parser.add_argument('--csv', required=True, help='CSV файл аннотации')
parser.add_argument('--ranges', default='', help='Диапазоны: "0-10000:Small,10000-50000:Medium,..."')
parser.add_argument('--min-area', type=float, default=0, help='Минимальная площадь')
parser.add_argument('--max-area', type=float, default=float('inf'), help='Максимальная площадь')
parser.add_argument('--output-csv', default='analyzed_data.csv', help='Файл для DataFrame')
parser.add_argument('--output-plot', default='area_distribution.png', help='Файл для графика')
parser.add_argument('--show-plot', action='store_true', help='Показать график')

return parser.parse_args()


def main():
try:
args = parse_arguments()

print("1. Загрузка данных...")
df = DataProcessor.create_dataframe_from_csv(args.csv)
print(f" Загружено {len(df)} записей")

print("\n2. Настройка диапазонов...")
if args.ranges:
area_ranges = DataProcessor.parse_custom_ranges(args.ranges)
print(" Используются пользовательские диапазоны")
else:
area_ranges = DataProcessor.create_default_area_ranges()
print(" Используются диапазоны по умолчанию")

print("\n3. Анализ изображений...")
df = DataProcessor.add_image_area_column(df, area_ranges)

print("\n4. Сортировка данных...")
sorted_df = DataProcessor.sort_by_area(df, ascending=False)

print("\n5. Фильтрация данных...")
filtered_df = DataProcessor.filter_by_area(sorted_df, args.min_area, args.max_area)

print("\n6. Расчет статистики...")
Visualizer.display_statistics(filtered_df)

print("\n7. Создание графика...")
fig = Visualizer.plot_area_histogram(filtered_df, area_ranges)

print("\n8. Сохранение результатов...")
filtered_df.to_csv(args.output_csv, index=False, encoding='utf-8')
print(f" DataFrame сохранен в {args.output_csv}")

fig.savefig(args.output_plot, dpi=300, bbox_inches='tight')
print(f" График сохранен в {args.output_plot}")

if args.show_plot:
plt.show()

print("\nАнализ завершен!")

except Exception as e:
print(f"Ошибка: {e}")
sys.exit(1)


if __name__ == "__main__":
main()
61 changes: 61 additions & 0 deletions lab4/visualizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import matplotlib.pyplot as plt
from typing import List, Tuple
import pandas as pd


class Visualizer:

@staticmethod
def plot_area_histogram(df: pd.DataFrame, area_ranges: List[Tuple[float, float, str]]) -> plt.Figure:
# Получаем все категории из диапазонов
categories = [category for _, _, category in area_ranges]

# Добавляем Error только если есть ошибки
error_count = len(df[df['area_category'] == "Error"])
if error_count > 0:
categories.append("Error")

counts = []
for category in categories:
count = len(df[df['area_category'] == category])
counts.append(count)

fig, ax = plt.subplots(figsize=(12, 6))
bars = ax.bar(categories, counts, color='skyblue', edgecolor='black')

# Используем разные цвета для Error
for i, (bar, category) in enumerate(zip(bars, categories)):
if category == "Error":
bar.set_color('lightcoral')

for bar, count in zip(bars, counts):
if count > 0:
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5,
str(count), ha='center', va='bottom')

ax.set_title('Распределение изображений по площади')
ax.set_xlabel('Диапазон площади')
ax.set_ylabel('Количество файлов')
ax.tick_params(axis='x', rotation=45)
plt.tight_layout()

return fig

@staticmethod
def display_statistics(df: pd.DataFrame) -> None:
print("\nСтатистика:")
print(f" Всего файлов: {len(df)}")

if 'image_area' in df.columns:
valid_df = df[df['area_category'] != 'Error']
error_count = len(df) - len(valid_df)

print(f" Валидных изображений: {len(valid_df)}")
print(f" Ошибочных файлов: {error_count}")

if len(valid_df) > 0:
print(f" Средняя площадь: {valid_df['image_area'].mean():,.0f}")
print(f" Минимальная площадь: {valid_df['image_area'].min():,.0f}")
print(f" Максимальная площадь: {valid_df['image_area'].max():,.0f}")
else:
print(" Нет валидных изображений для статистики")
Loading