Обработка изображений и компьютерное зрение — это очень широкое поле деятельности и самых разнообразных применений!
Например, недавно на хабре была статья "Сравнение изображений и генерация картинки отличий на Ruby", которая рассказывает о способе показать разницу между двумя версиями картинок, используемой сервисом Github.
Самый простой вариант — это обход каждого пикселя в первой картинке и проверке, есть ли этот пиксель во второй, но Github использует т.н. режим тональной разницы — при этом, мы так же обходим каждый пиксель в двух изображениях и вычисляем их разницу по каналам RGB.
Этот метод сравнения двух фотографий выдаёт картину отличий, вполне неплохо показывая изменения.
Недолго думая, я набросал этот метод сравнения для OpenCV:
//
// режим тональной разницы двух изображений
// - обходим каждый пиксель в двух изображениях и вычисляем их разницу по каналам RGB
//
//
// статья "Сравнение изображений и генерация картинки отличий на Ruby"
// http://habrahabr.ru/blogs/image_processing/117789/
//
//
// http://robocraft.ru
//
#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
int main(int argc, char* argv[])
{
IplImage *img1=0, *img2=0, *diff=0, *sub=0;
// дефолтные названия картинок для обработки
char file1[] = "tup.png";
char file2[] = "tup2.png";
// имя картинки задаётся первым параметром
char* filename1 = argc >= 2 ? argv[1] : file1;
// получаем картинку
img1 = cvLoadImage(filename1);
printf("[i] first image: %s\n", filename1);
// имя картинки задаётся первым параметром
char* filename2 = argc >= 3 ? argv[2] : file2;
// получаем картинку
img2 = cvLoadImage(filename2);
printf("[i] second image: %s\n", filename2);
if(!img1){
printf("[!] cant load image: %s\n", filename1);
return -1;
}
if(!img2){
printf("[!] cant load image: %s\n", filename2);
return -1;
}
if(img1->width!=img2->width || img1->height!=img2->height){
printf("[!] different image size!\n");
return -2;
}
// покажем изображения
cvNamedWindow( "image1");
cvShowImage( "image1", img1 );
cvNamedWindow( "image2");
cvShowImage( "image2", img2 );
// создаём картинку для хранения разницы
diff = cvCloneImage(img1);
sub = cvCloneImage(img1);
cvZero(diff);
// пробегаемся по всем пикселям изображения
for( int y=0; y<diff->height; y++ ) {
uchar* ptr1 = (uchar*) (img1->imageData + y * img1->widthStep);
uchar* ptr2 = (uchar*) (img2->imageData + y * img2->widthStep);
uchar* ptr = (uchar*) (diff->imageData + y * diff->widthStep);
for( int x=0; x<diff->width; x++ ) {
// 3 канала:
// B
ptr[3*x] = ptr1[3*x] + ptr2[3*x] - 2 * min(ptr1[3*x], ptr2[3*x]);
// G
ptr[3*x+1] = ptr1[3*x+1] + ptr2[3*x+1] - 2 * min(ptr1[3*x+1], ptr2[3*x+1]);
// R
ptr[3*x+2] = ptr1[3*x+2] + ptr2[3*x+2] - 2 * min(ptr1[3*x+2], ptr2[3*x+2]);
}
}
// вычитаем
cvSub(img2, img1, sub);
// выводим результат
cvNamedWindow( "diff");
cvShowImage( "diff", diff );
cvNamedWindow( "sub");
cvShowImage( "sub", sub );
// ждём нажатия клавиши
cvWaitKey(0);
// освобождаем ресурсы
cvReleaseImage(&img1);
cvReleaseImage(&img2);
cvReleaseImage(&diff);
cvReleaseImage(&sub);
// удаляем окна
cvDestroyAllWindows();
return 0;
}
А если добавить вычисления. (Нашел на хабре) Вот сcылочка: habrahabr.ru/post/115661/
То можно определить и расстояние.
l = L*K / ( W/x — 1 + K ), где
l – искомое расстояние до объекта, м;
L – длина «линейки», м;
W – длина «линейки» в пикселях, обычно совпадает с шириной изображения;
x – координата объекта на изображении;
K = (W — M) / M – коэффициент, отражающий наклон камеры, здесь M – координата середины «линейки».
А мне понравился метод. И вот генерация не картинки отличий, хотя кто мешает, а fgMask. И центра масс.
Знаю, что это плохой код. Если кто подскажет, как лучше буду благодарен.
Но это работает. И работает не плохо.
public class BackGround
{
CvBlobDetector _blobDetector = new CvBlobDetector();
CvBlobs blobs = new CvBlobs();
public Mat Back(ref Mat capture, Mat back, int sensetive, out int x, out int y)
{
int X = 0;
int Y = 0;
Image<Gray, Byte> maskCapture = capture.ToImage<Gray, Byte>();
Image<Gray, Byte> maskBack = back.ToImage<Gray, Byte>();
Image<Gray, Byte> result = new Image<Gray, byte>(capture.Width, capture.Height);
}
}
}
CvInvoke.Dilate(chanelsResult[0], chanelsResult[0], null, new Point(-1, -1), 10, BorderType.Constant, new MCvScalar());
//CvInvoke.Erode(chanelsResult[0], chanelsResult[0], null, new Point(-1, -1), 10, BorderType.Constant, new MCvScalar());
_blobDetector.Detect(chanelsResult[0], blobs);
Mat ResultM = (chanelsResult[0]).Mat;
blobs.FilterByArea(5000, int.MaxValue);
foreach (var pair in blobs)
{
CvBlob b = pair.Value;
CvInvoke.Rectangle(capture, b.BoundingBox, new MCvScalar(255.0, 255.0, 255.0), 2);
X = (int)b.Centroid.X;
Y = (int)b.Centroid.Y;
}
Комментарии (7)
RSS свернуть / развернутькакова практическая польза?
xtile
noonv
То можно определить и расстояние.
l = L*K / ( W/x — 1 + K ), где
l – искомое расстояние до объекта, м;
L – длина «линейки», м;
W – длина «линейки» в пикселях, обычно совпадает с шириной изображения;
x – координата объекта на изображении;
K = (W — M) / M – коэффициент, отражающий наклон камеры, здесь M – координата середины «линейки».
А мне понравился метод. И вот генерация не картинки отличий, хотя кто мешает, а fgMask. И центра масс.
Знаю, что это плохой код. Если кто подскажет, как лучше буду благодарен.
Но это работает. И работает не плохо.
public class BackGround
{
CvBlobDetector _blobDetector = new CvBlobDetector();
CvBlobs blobs = new CvBlobs();
public Mat Back(ref Mat capture, Mat back, int sensetive, out int x, out int y)
{
int X = 0;
int Y = 0;
Image<Gray, Byte> maskCapture = capture.ToImage<Gray, Byte>();
Image<Gray, Byte> maskBack = back.ToImage<Gray, Byte>();
Image<Gray, Byte> result = new Image<Gray, byte>(capture.Width, capture.Height);
Image<Gray, byte>[] chanelsCapture = maskCapture.Split();
Image<Gray, byte>[] chanelsBack = maskBack.Split();
Image<Gray, byte>[] chanelsResult = result.Split();
for (int i = 0; i <= capture.Height — 1; i++)
{
for (int j = 0; j <= capture.Width — 1; j++)
{
if (chanelsBack[0].Data[i, j, 0] — sensetive >= chanelsCapture[0].Data[i, j, 0] & chanelsBack[0].Data[i, j, 0] + sensetive >= chanelsCapture[0].Data[i, j, 0])
{
chanelsResult[0].Data[i, j, 0] = 255;
}
}
}
CvInvoke.Dilate(chanelsResult[0], chanelsResult[0], null, new Point(-1, -1), 10, BorderType.Constant, new MCvScalar());
//CvInvoke.Erode(chanelsResult[0], chanelsResult[0], null, new Point(-1, -1), 10, BorderType.Constant, new MCvScalar());
_blobDetector.Detect(chanelsResult[0], blobs);
Mat ResultM = (chanelsResult[0]).Mat;
blobs.FilterByArea(5000, int.MaxValue);
foreach (var pair in blobs)
{
CvBlob b = pair.Value;
CvInvoke.Rectangle(capture, b.BoundingBox, new MCvScalar(255.0, 255.0, 255.0), 2);
X = (int)b.Centroid.X;
Y = (int)b.Centroid.Y;
}
x = X;
y = Y;
return ResultM;
}
Annihilate
100b
Annihilate
RyDenisBak
Annihilate
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.