Пороговая обработка в задачах сегментации изображений
Основные понятия о представлении изображения. Определение величины порога с помощью гистограммы яркостей. Глобальная, локальная, адаптивная пороговая обработка. Метод дискриминантного критерия. Исследования на искусственных и предметных изображениях.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | дипломная работа |
Язык | русский |
Дата добавления | 23.12.2012 |
Размер файла | 5,1 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
{
case 0: for(int i=0;i<255;i++) raspred_func[i]=histogramma[i][0]; global_flag=0; break;
case 1: for(int i=0;i<255;i++) raspred_func[i]=histogramma[i][1]; global_flag=1; break;
case 2: for(int i=0;i<255;i++) raspred_func[i]=histogramma[i][2]; global_flag=2; break;
}
}
void memory()
{
px1 = new mRGB[pic[0].nRows * pic[0].nCols];
px2 = new mRGB[pic[0].nRows * pic[0].nCols];
}
void mat_ozhid_all() //мат. ожидание всего изображения
{
mat_ozhid_all_image=0;
for(int i=0;i<255;i++)
mat_ozhid_all_image+=i*raspred_func[i];
}
void disp_all() //дисперсия всего изображения
{
for(int i=0;i<255;i++)
{
disp_all_image+=(i-mat_ozhid_all_image)*(i-mat_ozhid_all_image);
}
}
void info_everykadr(int k) //информация о всем кадре
{
int all=0;
for(int i=0;i<255;i++)
all+=raspred_func[i];
for(int i=0;i<k;i++)
p0+=raspred_func[i]; //вероятность p0
for(int i=k+1;i<255;i++)
p1+=raspred_func[i]; //вероятность p1
p0/=all; //нормировка
p1/=all;
for(int i=0;i<k;i++)
m0+=i*raspred_func[i];
m1=(mat_ozhid_all_image-m0)/p1; //мат. ожидания
if(p0!=0) m0/=p0;
}
void megklass_disp() //вычисление межклассовой дисперсии
{
klass_disp=p0*(m0-mat_ozhid_all_image)*(m0-mat_ozhid_all_image)+p1*(m1-mat_ozhid_all_image)*(m1-mat_ozhid_all_image);
}
int diskrmnt_main(int what) //главная функция дискриминантной обработки
{
ulong max;
int porg=0;
FILE *f2;
f2=fopen("diskr_info.txt","w");
p0=0;
p1=0;
m0=0;
m1=0;
max=0;
klass_disp=0;
copy_histo(what); //получаем распределение
mat_ozhid_all(); //мат. ожидание всего изображения
disp_all(); //дисперсия всего изображения
memory(); //выделение памяти
for(int i=0;i<255;i++)
{
p0=0;
p1=0;
m0=0;
m1=0;
info_everykadr(i);
megklass_disp();
diskr_func[i]=klass_disp/disp_all_image;
}
for(int i=0;i<255;i++) //вычисляем абсолютный максимум дискриминантной функции
if(diskr_func[i]>max)
{
max=diskr_func[i];
porog[global_flag]=i;
}
for(int i=0;i<3;i++)
{
fprintf(f2,"porog[%i]=%i\n",i,porog[i]);
}
fclose(f2);
return porog[global_flag];
}
};
//******************************************************************************
//******************************************************************************
//**************** конец класс дискремининтного критерия *******************//
//******************************************************************************//******************************************************************************
diskr_class diskr; //элемент класса дискриминантная обработка
//******************************************************************************
//******************************************************************************
//****************************************** класс адаптивной обработки ******
//******************************************************************************//******************************************************************************
class adp_class{
public:
RGBpixmap pxmp;
void copy_1D_to_2D()
{
int ct;
mRGB** new_mass;
new_mass = new mRGB*[pxmp.nRows];
for(int i=0;i<pxmp.nRows;i++)
new_mass[i] = new mRGB[pxmp.nCols];
ct=-1;
for(int i=0;i<pxmp.nRows;i++)
{
for(int j=0;j<pxmp.nCols;j++)
{
ct++;
new_mass[i][j]=pixel[ct];
}
}
}
void obl_vich_intensiv(int m, int n, int obl) //вычисляем текущее территориальное расположение пикселя
{
int ct=0;
switch(obl) //определяем область вокруг центрального пикселя
{
case 0: //левый нижний угол
for(int j=n;j<n+KK+1;j++)
for(int i=m;i<m+1+KK;i++)
{
if(i!=m && j!=n) mass_obl[ct]=pxmp.getPixel(i,j);
ct++;
}
break;
case 1: //нижняя граница
for(int j=n;j<n+KK+1;j++)
for(int i=m-KK;i<m+1+KK;i++)
{
if(i!=m && j!=n) mass_obl[ct]=pxmp.getPixel(i,j);
ct++;
}
break;
case 3: //правая граница
for(int j=n-KK;j<n+KK+1;j++)
for(int i=m-KK;i<m+1;i++)
{
if(i!=m && j!=n) mass_obl[ct]=pxmp.getPixel(i,j);
ct++;
}
break;
case 2: //правый нижний угол
for(int j=n;j<n+KK+1;j++)
for(int i=m-KK;i<m+1;i++)
{
if(i!=m && j!=n) mass_obl[ct]=pxmp.getPixel(i,j);
ct++;
}
break;
case 4: //правый верхний угол
for(int j=n-KK;j<n+1;j++)
for(int i=m-KK;i<m+1;i++)
{
if(i!=m && j!=n) mass_obl[ct]=pxmp.getPixel(i,j);
ct++;
}
break;
case 5: //верхняя граница
for(int j=n-KK;j<n+1;j++)
for(int i=m-KK;i<m+1+KK;i++)
{
if(i!=m && j!=n) mass_obl[ct]=pxmp.getPixel(i,j);
ct++;
}
break;
case 6: //левый верхний угол
for(int j=n-KK;j<n+1;j++)
for(int i=m;i<m+1+KK;i++)
{
if(i!=m && j!=n) mass_obl[ct]=pxmp.getPixel(i,j);
ct++;
}
break;
case 7: //левая граница
for(int j=n-KK;j<n+1+KK;j++)
for(int i=m;i<m+1+KK;i++)
{
if(i!=m && j!=n) mass_obl[ct]=pxmp.getPixel(i,j);
ct++;
}
break;
case 8: //центральная область
for(int j=n-KK;j<n+1+KK;j++)
for(int i=m-KK;i<m+1+KK;i++)
{
if(i!=m && j!=n && i>=0 && j>=0) mass_obl[ct]=pxmp.getPixel(i,j);
ct++;
}
break;
}
}
void vich_loc_intensiv_tchk() //основная процедура адаптивной обработки
{
double sred_intens, delta_max, delta_min,t;
FILE *f5;
mRGB tek;
mRGB newcolor_o,newcolor_f;
mRGB null;
mRGB *px;
px = new mRGB[pic[0].nCols*pic[0].nRows];
double tek_intens;
int max=0,fflag;
int min=0;
int po=0,pf=0,ct=0;
sred_intens=0.0;
newcolor_o.r=255; //новый цвет объекта
newcolor_o.g=255;
newcolor_o.b=255;
newcolor_f.r=0; //новый цвет фона
newcolor_f.g=0;
newcolor_f.b=0;
null.r=0;
null.g=0;
null.b=0;
int oblast=(2*KK+1)*(2*KK+1); //вычисляем область соседей
for(int i=0;i<oblast-1;i++)
{
mass_obl[i]=null;
}
fflag=0;
rez=fopen("rezult.txt","w"); //файл результата
fprintf(rez,"Method: adapt\n\n");
//обработка всей сетки
for(int i=0;i<pic[0].nRows;i++)
{
for(int j=0;j<pic[0].nCols;j++)
{ //различные ситуации
if(i==0 && j==0) obl_vich_intensiv(j,i,0);
if(i==0 && j==pic[0].nCols-1) obl_vich_intensiv(j,i,2);
if(i==0 && j!=0) obl_vich_intensiv(j,i,1);
if(j==pic[0].nCols-1 && i!=pic[0].nRows-1) obl_vich_intensiv(j,i,3);
if(j==pic[0].nCols-1 && i==pic[0].nRows-1) obl_vich_intensiv(j,i,4);
if(i==pic[0].nRows-1 && j!=0) obl_vich_intensiv(j,i,5);
if(j==0 && i==pic[0].nRows-1) obl_vich_intensiv(j,i,6);
if(j==0 && i!=0) obl_vich_intensiv(j,i,7);
if(i!=0 && j!=0 && i!=pic[0].nRows-1 && j!=pic[0].nCols-1) obl_vich_intensiv(j,i,8);
tek=pic[0].getPixel(j,i);
tek_intens=0.3*tek.r+0.59*tek.g+0.11*tek.b; //яркость
for(int k=0;k<oblast-1;k++)
{
sred_intens+=0.3*mass_obl[k].r+0.59*mass_obl[k].g+0.11*mass_obl[k].b; //средняя интенсивность в точке
}
sred_intens/=oblast;
if (sred_intens>max) max=sred_intens; //максимум
if (sred_intens<min) min=sred_intens; //минимум
delta_max=abs(max-sred_intens); //приращение max
delta_min=abs(min-sred_intens); //приращение min
if(delta_max>delta_min) t=alfa*(2./3.*min+1./3.*sred_intens); //определяем параметр t
else t=alfa*(1./3.*min+2./3.*sred_intens);
ct++;
if ( (sred_intens-tek_intens)>t) //условие принадлежности пикселя объекту
{
pic[0].setPixel(j,i,newcolor_f);
fprintf(rez,"x=%i\ty=%i\tR=%i\tG=%i\tB=%i\tRGB=%lf\n",j,i,tek.r,tek.g,tek.b,tek_intens);
po++;
}
else
{
pic[0].setPixel(j,i,newcolor_o);
pf++;
}
fflag++;
}
}
fprintf(rez,"\n\nPixel_in_object = %i\nPixel_in_fone = %i\nPixel_in_image = %i\n",po,pf,ct);
fclose(rez);
}
void everything()
{
copy_1D_to_2D();
vich_loc_intensiv_tchk();
}
};
//******************************************************************************
//******************************************************************************
//*********************************** конец класс адаптивной обработки *********
//******************************************************************************
//******************************************************************************
adp_class lc; //элемент класса адаптивная обработка
//процедура непосредственного перераспределения пикселей к классам для дискриминантного метода
int func_adpt_porog(int num,int porog[3])
{
int rez=0;
if(pixel[num].r<=porog[0] && pixel[num].g<=porog[1] && pixel[num].b<=porog[2]) rez=1;
else rez=0;
return rez;
}
void adpt_segmentation()
{
long ct=0;
int cvet_fon,cvet_object,po,pf,flag;
cvet_fon=0;
cvet_object=255;
ct=0;
po=0;
pf=0;
i_flag=0;
j_flag=0;
for (int i=0; i<pic[0].nRows;i++) //цикл по строкам
{
for(int j=0; j<pic[0].nCols; j++) //цикл по столбцам
{
flag=func_adpt_porog(ct,adpt_porog); //определение принадлежности пикселя
if (flag==1) //установка нового значения пикселя (фон)
{
pic[whichPic].pixel_in_fone(ct);
fprintf(rez,"x=%i\ty=%i\tR=%i\tG=%i\tB=%i\tRGB=%lf\n",j,i,pixel[ct].r,pixel[ct].g,pixel[ct].b,0.3*pixel[ct].r+0.59*pixel[ct].g+0.11*pixel[ct].b);
pixel[ct].r=cvet_fon;
pixel[ct].g=cvet_fon;
pixel[ct].b=cvet_fon;
po++;
}
else //установка нового значения пикселя (объект)
{
pic[whichPic].pixel_in_object(ct);
pixel[ct].r=cvet_object;
pixel[ct].g=cvet_object;
pixel[ct].b=cvet_object;
pf++;
}
ct++;
}
}
fprintf(rez,"\n\nPixel_in_object = %i\nPixel_in_fone = %i\nPixel_in_image = %i\n",po,pf,ct);
}
//инвертирование изображения
void invert()
{
int ct;
int c=1;
ct=-1;
for(int i=0;i<pic[0].nRows;i++)
{
for(int j=0;j<pic[0].nCols;j++)
{
ct++;
pixel[ct].r=255-pixel[ct].r;
pixel[ct].g=255-pixel[ct].g;
pixel[ct].b=255-pixel[ct].b;
}
}
}
//построение гистограмм
void build_histogramma()
{
for(int i=0;i<256;i++)
for(int j=0;j<3;j++)
{
histogramma[i][j]=0;
}
for(int i=0;i<pic[whichPic].nCols*pic[whichPic].nRows;i++)
{
histogramma[pixel[i].r][0]++;
histogramma[pixel[i].g][1]++;
histogramma[pixel[i].b][2]++;
}
}
//****** обработка вывода на экран гистограммы R (Open GL) *********************
void myDisplayHistoR(void)
{
int a=0;
a=256+otstyp;
glClearColor(1.0,1.0,1.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
glBegin(GL_LINES);
for(int i=otstyp;i<a;i++)
{
glVertex2i(i,0);
glVertex2i(i,histogramma[i-otstyp][0]/delR);
}
glEnd();
glFlush ();
}
//********** обработка действий клавиатурой (Open GL) *******//
//основная идея запуска каждой из обработок
void myKeys(unsigned char key, int x, int y)
{
switch(key)
{
case 'q': exit(0);
case 's': whichPic=1-whichPic; break;
case 'p': pic[0].read(0,0,200,200); break;
case 'a': loc2.loc2al_glob_porog(); what_draw=2; break; //локальная пороговая обработка
case 'i': pic[whichPic].copy_image(pixel,pixel2); what_draw=1; break; //восстановление исходного изображения
case 'g': glob_porog(); what_draw=1; break; //глобальная пороговая обработка
case 'l': lc.everything(); what_draw=1; break; //адаптивная пороговая обработка
case 'd': rez=fopen("rezult.txt","w");
fprintf(rez,"Method: diskriminant\n\n");
for(int i=0;i<3;i++) //вычисляем порог для каждой из составляющих R,G и B
adpt_porog[i]=diskr.diskrmnt_main(i);
adpt_segmentation(); //дискриминантная сегментация
what_draw=1;
fclose(rez);
break;
case 'e': etalon_videl_only_black(); what_draw=1; break; //выделение эталона
case 'o': invert(); what_draw=1; break; //инвертирование
}
glutPostRedisplay(); //обновления экрана (Open GL)
}
}
Примеры обработки событий (Windows Forms):
#pragma once
#include "windows.h"
#include "iostream"
#include <conio.h>
#include "PROG.CPP" //основной файл со всеми важнейшими классами и обработками изображения
#include "FormHelp.h" //библиотека ПОМОЩЬ
#include "stdafx.h"
#include "ShowImage.h" //библиотека изображения (вывода на экран)
#include "ok.h" //библиотека отдельной глобальной обработки
#include "histo.h" //библиотека гистограмм
#include "loc.h" //библиотека отдельной локальной обработки
#include "Diskr.h" //библиотека отдельной обработки методом дискриминантного критерия
#include "Adapt.h" //библиотека отдельной адаптивной обработки
using namespace std;
namespace Interface { //пространство ИНТЕРФЕЙС
//использование функций, классов и т.д. следующих компонент:
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent(); //параметры основной формы
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::Button^ button1;
private: System::Windows::Forms::GroupBox^ groupBox1;
private: System::Windows::Forms::Button^ OpenImage;
private: System::Windows::Forms::TextBox^ ImageTextBox;
private: System::Windows::Forms::OpenFileDialog^ openFileDialog1;
private: System::Windows::Forms::GroupBox^ groupBox2;
private: System::Windows::Forms::GroupBox^ groupBox3;
//и так далее. Здесь определяются все объекты, расположенные на форме.
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
//генерируется код для обработки всех свойств всех объектов
void InitializeComponent(void)
{
//инициализация всех объектов
this->button1 = (gcnew System::Windows::Forms::Button());
this->groupBox1 = (gcnew System::Windows::Forms::GroupBox());
this->OpenImage = (gcnew System::Windows::Forms::Button());
// button1
//
this->button1->BackColor = System::Drawing::Color::Azure;
this->button1->Location = System::Drawing::Point(0, 14);
this->button1->Name = L"button1";
this->button1->Size = System::Drawing::Size(139, 21);
this->button1->TabIndex = 0;
this->button1->Text = L"Описание программы";
this->button1->UseVisualStyleBackColor = false;
this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
//и так далее. Здесь определяются все основные свойства объектов, расположенных на форме.
//пример обработка нажатия кнопки "кнопка помощь"
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { FormHelp ^f = gcnew FormHelp;
f->ShowDialog();
}
//пример обработки нажатия кнопки "показать изображение"
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
//*************************************************
//”ручной” перевод из типа String^ в Char*
//*************************************************
int b=1;
String^ fn=openFileDialog1->FileName;
if (fn=="") b=0;
int z;
int *r1,*g1,*b1;
char *qwerty,qw;
short wq;
int l;
l=openFileDialog1->FileName->Length;
qwerty=new char[l];
for(int i=0;i<l;i++){
qwerty[i]=Convert::ToInt16(openFileDialog1->FileName[i]);
}
int kol=0;
qw=qwerty[2];
for(int i=0;i<l;i++)
{
if(qwerty[i]==qw)
kol++;
}
char *ir;
ir = new char[l+kol+1];
for(int i=0,j=0;i<l+kol;i++,j++)
{
ir[i]=qwerty[j];
if(ir[i]==qw) { i++; ir[i]=qw; }
}
ir[l+kol]='\0';
//*************************************************
//конец ”ручного” перевода из типа String^ в Char*
//*************************************************
globa::filename=ir; //передаем в присоединенную PROG.CPP параметр
if ( checkBox1->Checked==1)
{
z=1;
int g=globa::main2();
r1 = new int[globa::pic[globa::whichPic].nCols*globa::pic[globa::whichPic].nRows];
g1 = new int[globa::pic[globa::whichPic].nCols*globa::pic[globa::whichPic].nRows];
b1 = new int[globa::pic[globa::whichPic].nCols*globa::pic[globa::whichPic].nRows];
int ct=-1;
for(int i=0;i<globa::pic[globa::whichPic].nRows;i++) //если есть инвертирование изображения
{
for(int j=0;j<globa::pic[globa::whichPic].nCols;j++)
{
ct++;
globa::pixel[ct].r=255-globa::pixel[ct].r;
globa::pixel[ct].g=255-globa::pixel[ct].g;
globa::pixel[ct].b=255-globa::pixel[ct].b;
}
}
ct=-1;
for(int i=0;i<globa::pic[globa::whichPic].nRows;i++)
{
for(int j=0;j<globa::pic[globa::whichPic].nCols;j++)
{
ct++;
r1[ct]=globa::pixel[ct].r;
g1[ct]=globa::pixel[ct].g;
b1[ct]=globa::pixel[ct].b;
}
}
}
ShowImage ^si = gcnew ShowImage(b,z,globa::pic[globa::whichPic].nRows,globa::pic[globa::whichPic].nCols,r1,g1,b1,fn); //создаем изображение и вызываем функцию на другой форме
if(b==1) si->ShowDialog();
}
//пример вывода изображения на экран с использованием Windows Forms и //сформированного массива pixel[] в программе PROG.CPP
public ref class ShowImage : public System::Windows::Forms::Form
{
public:
ShowImage(int a, int y,int CC, int RR,int *r, int *g, int *b, String^ filename)
{
int H,W;
if (a==1)
{
Bitmap^ MyImage;
MyImage = gcnew Bitmap(filename); //создаем тип Bitmap
Bitmap^ MyImage2;
MyImage2 = gcnew Bitmap(filename);
H=MyImage->Height;
W=MyImage->Width;
if (y==1)
{
int ct=RR*CC;
for(int i=0;i<CC;i++)
{
for(int j=0;j<RR;j++)
{
ct--;
MyImage->SetPixel(RR-j- //устанавливаем пиксели 1,i,Color::FromArgb(r[ct],g[ct],b[ct]));
}
}
}
InitializeComponent(W,H);
ShowImagePictureBox->ClientSize = System::Drawing::Size( W, H );
ShowImagePictureBox->Image = dynamic_cast<Image^>(MyImage);
}
else if(a==0) {
String^ message;
message="Ошибка!";
MessageBox::Show("Файл не был выбран!",message);
}
}
//пример вывода сообщения на экран
private: System::Void Developer_Click(System::Object^ sender, System::EventArgs^ e) {
String^ message;
message="Разработчик:";
MessageBox::Show("Bachelor Version 2.2\nКартавцев А.М., пм-51 (2009г.)",message);
}
//основная программа запуска
#include "stdafx.h"
#include "Form1.h"
using namespace Interface;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
int b;
// Enabling Windows XP visual effects before any controls are created
//b=main2();
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Create the main window and run it
Application::Run(gcnew Form1()); //запускаем основную форму
return 0;
}
Размещено на Allbest.ru
Подобные документы
Современные системы текстурного анализа изображений. Примеры текстурной сегментации одноканальных изображений. Использование признаков, полученных на основе гистограммы яркостей второго порядка, для классификации спектрозональных аэрофотоснимков.
реферат [573,5 K], добавлен 15.01.2017Яркость точек и гистограммы изображения. Изменение яркости и контрастности. Метод ранговой фильтрации с оценкой середины диапазона. Наложение шумов на изображение. Преобразование изображения в негатив. Получение матрицы яркостей и построение гистограмм.
курсовая работа [1,5 M], добавлен 11.12.2012Методы обработки растровых изображений (кластеризация, пороговая и интерактивная сегментация). Разработка программного модуля для системы мониторинга биосферы и дистанционного зондирования. Создание пользовательского интерфейса программного модуля.
курсовая работа [2,2 M], добавлен 29.04.2015Выбор методов обработки и сегментации изображений. Математические основы примененных фильтров. Гистограмма яркости изображения. Программная реализация комплексного метода обработки изображений. Тестирование разработанного программного обеспечения.
курсовая работа [1,3 M], добавлен 18.01.2017История появления и основные понятия графического дизайна. Выявление главных преимуществ и недостатков недеструктивной обработки изображений. Сравнение деструктивной и недеструктивной обработки изображений. Сущность и особенности двухмерной графики.
реферат [5,2 M], добавлен 05.05.2023Общий алгоритм сравнения двух изображений. Метод максимальных площадей. Метод гистограмм. Подготовка изображения к распознаванию. Моделирование многомерной функции. Распределение векторов. Деформируемые модели. Реализация программного обеспечения.
дипломная работа [384,2 K], добавлен 29.09.2008Обработка изображений на современных вычислительных устройствах. Устройство и представление различных форматов изображений. Исследование алгоритмов обработки изображений на базе различных архитектур. Сжатие изображений на основе сверточных нейросетей.
дипломная работа [6,1 M], добавлен 03.06.2022Компьютерная графика и обработка изображений электронно-вычислительными машинами являются наиболее важным аспектом использования ЭВМ во всех сферах человеческой деятельности. Разработка "подсистемы линейной сегментации", описание алгоритма и логики.
дипломная работа [1,1 M], добавлен 23.06.2008Элементы и принципы графического дизайна в художественном образовании. Разработка графических изображений средствами Adobe Photoshop. Обработка изображения с помощью Photoshop. Подготовка изображения с прозрачным фоном. Плавное слияние двух изображений.
курсовая работа [2,5 M], добавлен 27.11.2012Описание метода обработки "Выделение контурных линий" и особенностей его применения и программной реализации. Способы увеличения контрастности. Значение правильного подбора формы гистограммы для качества компьютерной обработки растрового изображения.
курсовая работа [940,2 K], добавлен 24.06.2013