Diplom_29-06 (1221240), страница 6
Текст из файла (страница 6)
CvArr – массив – его можно считать «абстрактным базовым классом» для CvMat При работе с изображениями также возникает вопрос маштабирования (уменьшение или увеличение изображения).
В OpenCV это реализуется функцией cvResize().
-
Реализация алгоритмов YUV (YCbCr)
YUV преобразование используется достаточно долгое время в различных системах, связанных со статическими и динамическими изображениями. Компонента яркости Y идеально подходит для передачи сигнала в телевизорах, поддерживающих только черно-белое изображение. В цветном телевизоре сигналы U и V позволяли восстанавливать всю картинку в цвете. С приходом цифровой обработки данных преобразование YUV нашло применение в алгоритмах сжатия изображений JPEG, MPEG4, H.264/AVC и в быстро развивающемся сегодня широкоформатном телевидении (HDTV).
Прямое преобразование из RGB в YCbCr:
Y = 0,299R + 0,587G + 0,114B;
Cb = –0,168736R – 0,331264G + 0,5B + 128; (3)
Cr = 0,5R – 0,418688G – 0,081312B + 128.
Обратное преобразование из YCbCr в RGB:
R =Y + 1,402(Cr – 128);
G =Y – 0,7141(Cr – 128) – 0,34414(Cb – 128); (4)
B =Y + 1,772(Cb – 128).
Формат 4:4:4 определяется тем, что каждая из трех компонент Y'CbCr имеет одинаковую частоту дискретизации. Получил применение в дорогих сканерах и кинематографическом пост-продакшн производстве. Обычно, для предоставления такой пропускной способности используется двухканальный интерфейс HD-SDI, стандарта SMPTE 372M. Первое подключение для передачи сигнала 4:2:2, второе подключение – для сигнала 0:2:2, в сочетании будет передано 4:4:4.
Формат данных YUV 4:4:4 передает 24 бита на один пиксель. Каждому пикселю присваивается уникальное значение Y, U – содержащее 1 байт для каждого значения, что делает его наиболее простым формат понимания.
Перевод RGB to YUV 4:4:4
case 0: ///RGB to YUV 4:4:4
{
cv::Mat imageYUV420_YUV = cvCreateMat( imageINPUT.rows, imageINPUT.cols, CV_8UC3 );
std::vector<cv::Mat> channelsYUV420_YUV;
cv::split(imageYUV420_YUV,channelsYUV420_YUV);
///Перевод в цветовую раскладку YUV
for( int i = 0; i < imageINPUT.rows; i++ )
{
for( int j = 0; j < imageINPUT.cols; j++ )
{
int R=ChannelsInInput[0].at<uchar>(i,j);
int G=ChannelsInInput[1].at<uchar>(i,j);
int B=ChannelsInInput[2].at<uchar>(i,j);
channelsYUV420_YUV[0].at<uchar>(i,j)=0.299*R+0.587*G+0.114*B;
channelsYUV420_YUV[1].at<uchar>(i,j)=-0.14713*R-0.28886*G+0.436*B+128;
channelsYUV420_YUV[2].at<uchar>(i,j)=0.615*R-0.51499*G-0.10001*B+128;
//channelsYUV420_YUV[1].at<uchar>(i,j)=-0.168736*R-0.331264*G+0.5*B+128;
//channelsYUV420_YUV[2].at<uchar>(i,j)=0.5*R-0.418688*G-0.081312*B+128;
}
}
///Архивирование
///А теперь нужно разархивировать изображение
for( int i = 0; i < imageOUTPUT.rows; i++ )
{
for( int j = 0; j < imageOUTPUT.cols; j++ )
{
int R = (float)channelsYUV420_YUV[0].at<uchar>(i,j) + 1.13983 * ((float)channelsYUV420_YUV[2].at<uchar>(i,j)-128);
//int R = (float)channelsYUV420_YUV[0].at<uchar>(i,j) + 1.402 * ((float)channelsYUV420_YUV[2].at<uchar>(i,j)-128);
if (R>255) R=255;
if (R<0) R=0;
int G = (float)channelsYUV420_YUV[0].at<uchar>(i,j) -0.39465 * ((float)channelsYUV420_YUV[1].at<uchar>(i,j)-128) - 0.58060 * ((float)channelsYUV420_YUV[2].at<uchar>(i,j)-128);
//int G = (float)channelsYUV420_YUV[0].at<uchar>(i,j) -0.34414 * ((float)channelsYUV420_YUV[1].at<uchar>(i,j)-128) - 0.71414 * ((float)channelsYUV420_YUV[2].at<uchar>(i,j)-128);
if (G>255) G=255;
if (G<0) G=0;
int B = (float)channelsYUV420_YUV[0].at<uchar>(i,j) + 2.03211 * ((float)channelsYUV420_YUV[1].at<uchar>(i,j)-128);
//int B = (float)channelsYUV420_YUV[0].at<uchar>(i,j) + 1.772 * ((float)channelsYUV420_YUV[1].at<uchar>(i,j)-128);
if (B>255) B=255;
if (B<0) B=0;
ChannelsInOutput[0].at<uchar>(i,j)=(uchar)R;
ChannelsInOutput[1].at<uchar>(i,j)=(uchar)G;
ChannelsInOutput[2].at<uchar>(i,j)=(uchar)B;
}
}
wxString mystring4 = wxString::Format(wxT("%d%s"), imageINPUT.channels()*imageINPUT.cols*imageINPUT.rows," байт");
StaticText4->SetLabelText(mystring4);
wxString mystring5 = wxString::Format(wxT("%d%s"), imageYUV420_YUV.channels()*imageYUV420_YUV.cols*imageYUV420_YUV.rows," байт");
StaticText5->SetLabelText(mystring5);
wxString mystringR = wxString::Format(wxT("%f"), 1.0 );
StaticTextRatio->SetLabelText(mystringR);
if (CheckBox1->GetValue()==true)
{
cvNamedWindow("Y", CV_WINDOW_AUTOSIZE);
cv::imshow("Y", channelsYUV420_YUV[0]);
cvNamedWindow("U", CV_WINDOW_AUTOSIZE);
cv::imshow("U", channelsYUV420_YUV[1]);
cvNamedWindow("V", CV_WINDOW_AUTOSIZE);
cv::imshow("V", channelsYUV420_YUV[2]);
}
cv::merge(channelsYUV420_YUV,imageYUV420_YUV);
cv::resize(imageYUV420_YUV, imageYUV420_YUV, cv::Size(SIZE_IMAGE, SIZE_IMAGE), 0.0, 0.0);
wxImage aswxImage2 = wxImage(imageYUV420_YUV.cols, imageYUV420_YUV.rows, imageYUV420_YUV.data, true);
wxBitmap bitmap2 = wxBitmap(aswxImage2);
StaticBitmap2->SetBitmap(bitmap2);
break;
}
Формат 4:2:2 получил распространение в научных исследованиях, профессиональных системах и формате MPEG-2. Рекомендация 601 определяет стандарт полного цифрового видеосигнала с соотношением частот дискретизации яркостного и цветоразностных сигналов как 4:2:2. В каждой строке передается полный сигнал яркости, а для цветоразностных сигналов производится выборка каждого второго отсчета. Таким образом, цветовое горизонтальное разрешение снижается вдвое.
Реализация YUV 4:2:2
case 1: ///RGB to YUV 4:2:2
{
cv::Mat imageYUV420_YUV = cvCreateMat( imageINPUT.rows, imageINPUT.cols, CV_8UC3 );
cv::Mat imageYUV420_Y = cvCreateMat( imageINPUT.rows, imageINPUT.cols, CV_8UC1 );
cv::Mat imageYUV420_UV = cvCreateMat( imageINPUT.rows, imageINPUT.cols/2, CV_8UC2 );
std::vector<cv::Mat> channelsYUV420_UV;
cv::split(imageYUV420_UV,channelsYUV420_UV);
std::vector<cv::Mat> channelsYUV420_YUV;
cv::split(imageYUV420_YUV,channelsYUV420_YUV);
///Перевод в цветовую раскладку YUV
for( int i = 0; i < imageINPUT.rows; i++ )
{
for( int j = 0; j < imageINPUT.cols; j++ )
{
int R=ChannelsInInput[0].at<uchar>(i,j);
int G=ChannelsInInput[1].at<uchar>(i,j);
int B=ChannelsInInput[2].at<uchar>(i,j);
channelsYUV420_YUV[0].at<uchar>(i,j)=0.299*R+0.587*G+0.114*B;
channelsYUV420_YUV[1].at<uchar>(i,j)=-0.14713*R-0.28886*G+0.436*B+128;
channelsYUV420_YUV[2].at<uchar>(i,j)=0.615*R-0.51499*G-0.10001*B+128;
}
}
///Архивирование
imageYUV420_Y=channelsYUV420_YUV[0];
for( int i = 0; i < imageINPUT.rows; i++ )
{
for( int j = 0; j < imageINPUT.cols; j+=2 )
{
int Uthis=channelsYUV420_YUV[1].at<uchar>(i,j);
int Uright=channelsYUV420_YUV[1].at<uchar>(i,j+1);
int Vthis=channelsYUV420_YUV[2].at<uchar>(i,j);
int Vright=channelsYUV420_YUV[2].at<uchar>(i,j+1);
channelsYUV420_UV[0].at<uchar>(i,j/2)=(Uthis+Uright)/2;
channelsYUV420_UV[1].at<uchar>(i,j/2)=(Vthis+Vright)/2;
}
}
if (CheckBox1->GetValue()==true)
{
cvNamedWindow("Y", CV_WINDOW_AUTOSIZE);
cv::imshow("Y", imageYUV420_Y);
cvNamedWindow("U", CV_WINDOW_AUTOSIZE);
cv::imshow("U", channelsYUV420_UV[0]);
cvNamedWindow("V", CV_WINDOW_AUTOSIZE);
cv::imshow("V", channelsYUV420_UV[1]);
}
cv::merge(channelsYUV420_YUV,imageYUV420_YUV);
cv::resize(imageYUV420_YUV, imageYUV420_YUV, cv::Size(SIZE_IMAGE, SIZE_IMAGE), 0.0, 0.0);
wxImage aswxImage2 = wxImage(imageYUV420_YUV.cols, imageYUV420_YUV.rows, imageYUV420_YUV.data, true);
wxBitmap bitmap2 = wxBitmap(aswxImage2);
StaticBitmap2->SetBitmap(bitmap2);
///А теперь нужно разархивировать изображение
for( int i = 0; i < imageOUTPUT.rows; i++ )
{
for( int j = 0; j < imageOUTPUT.cols; j++ )
{
int R = (float)imageYUV420_Y.at<uchar>(i,j) + 1.13983 * ((float)channelsYUV420_UV[1].at<uchar>(i,j/2)-128);
if (R>255) R=255; if (R<0) R=0;
int G = (float)imageYUV420_Y.at<uchar>(i,j) -0.39465 * ((float)channelsYUV420_UV[0].at<uchar>(i,j/2)-128) - 0.58060 * ((float)channelsYUV420_UV[1].at<uchar>(i,j/2)-128);
if (G>255) G=255; if (G<0) G=0;
int B = (float)imageYUV420_Y.at<uchar>(i,j) + 2.03211 * ((float)channelsYUV420_UV[0].at<uchar>(i,j/2)-128);
if (B>255) B=255;
if (B<0) B=0;
ChannelsInOutput[0].at<uchar>(i,j)=(uchar)R;
ChannelsInOutput[1].at<uchar>(i,j)=(uchar)G;
ChannelsInOutput[2].at<uchar>(i,j)=(uchar)B;
}
}
wxString mystring4 = wxString::Format(wxT("%d%s"), imageINPUT.channels()*imageINPUT.cols*imageINPUT.rows," байт");
StaticText4->SetLabelText(mystring4);
wxString mystring5 = wxString::Format(wxT("%d%s"), imageYUV420_Y.cols*imageYUV420_Y.rows+imageYUV420_UV.channels()*imageYUV420_UV.cols*imageYUV420_UV.rows," байт");
StaticText5->SetLabelText(mystring5);
wxString mystringR = wxString::Format(wxT("%f"), (float)(imageINPUT.channels()*imageINPUT.cols*imageINPUT.rows) / (float)(imageYUV420_Y.cols*imageYUV420_Y.rows+imageYUV420_UV.channels()*imageYUV420_UV.cols*imageYUV420_UV.rows) );
StaticTextRatio->SetLabelText(mystringR);
break;
}
Формат 4:2:0 при дискретизации для цветоразностных компонентов Cb и Cr отбрасывается каждый второй отсчёт по горизонтали и по вертикали. Есть три варианта схем 4:2:0, имеющих различные горизонтальные и вертикальные размещения отсчётов:
-
отсчеты цветоразностных компонентов в формате 4:2:0, принятом в системе компрессии MPEG-2, не совмещены с отсчётами яркостной составляющей:
-
в JPEG / JFIF, H.261 и MPEG-1, Cb и Cr совмещены и располагаются между альтернативными отсчетами яркости;
-
в 4:2:0 DV, отсчёты цветоразностных компонентов Cb и Cr совмещены с отсчётами яркостной составляющей изображения, может быть получен из прототипной структуры 4:2:2 путем поочередного исключения одного цветоразностного компонента в каждой второй строке каждого поля.
Ниже приведена реализация алгоритма 4:2:0
case 2: ///RGB to YUV 4:2:0
{
///Объявление массивов для хранения сжатого изображения
cv::Mat imageYUV420_YUV = cvCreateMat( imageINPUT.rows, imageINPUT.cols, CV_8UC3 );
cv::Mat imageYUV420_Y = cvCreateMat( imageINPUT.rows, imageINPUT.cols, CV_8UC1 );
cv::Mat imageYUV420_UV = cvCreateMat( imageINPUT.rows/2, imageINPUT.cols/2, CV_8UC2 );
///Разделение его на компоненты
std::vector<cv::Mat> channelsYUV420_UV;
cv::split(imageYUV420_UV,channelsYUV420_UV);
std::vector<cv::Mat> channelsYUV420_YUV;
cv::split(imageYUV420_YUV,channelsYUV420_YUV);
///Перевод в цветовую раскладку YUV
for( int i = 0; i < imageINPUT.rows; i++ )
{
for( int j = 0; j < imageINPUT.cols; j++ )
{
int R=ChannelsInInput[0].at<uchar>(i,j);
int G=ChannelsInInput[1].at<uchar>(i,j);
int B=ChannelsInInput[2].at<uchar>(i,j);
///Вычисление Y U V составляющих
channelsYUV420_YUV[0].at<uchar>(i,j)=0.299*R+0.587*G+0.114*B;
channelsYUV420_YUV[1].at<uchar>(i,j)=-0.14713*R-0.28886*G+0.436*B+128;
channelsYUV420_YUV[2].at<uchar>(i,j)=0.615*R-0.51499*G-0.10001*B+128;
}
}
///Архивирование
imageYUV420_Y=channelsYUV420_YUV[0]; ///Компонента Y имеет тот же размер поэтому просто приравнивается
for( int i = 0; i < imageINPUT.rows; i+=2 )
{
for( int j = 0; j < imageINPUT.cols; j+=2 )
{
///Беруться значения окружающих 4 пикселей
int Uthis=channelsYUV420_YUV[1].at<uchar>(i,j);
int Uright=channelsYUV420_YUV[1].at<uchar>(i+1,j);
int Udown=channelsYUV420_YUV[1].at<uchar>(i,j+1);
int Udiag=channelsYUV420_YUV[1].at<uchar>(i+1,j+1);
int Vthis=channelsYUV420_YUV[2].at<uchar>(i,j);
int Vright=channelsYUV420_YUV[2].at<uchar>(i+1,j);
int Vdown=channelsYUV420_YUV[2].at<uchar>(i,j+1);
int Vdiag=channelsYUV420_YUV[2].at<uchar>(i+1,j+1);
///Значения усредняются и записываются в соответстующие массивы
channelsYUV420_UV[0].at<uchar>(i/2,j/2)=(Uthis+Uright+Udown+Udiag)/4;
channelsYUV420_UV[1].at<uchar>(i/2,j/2)=(Vthis+Vright+Vdown+Vdiag)/4;
}
}
///Вывод на экран кадров данных после кодирования















