I am trying to copy one image layer to another image ROI. My code is given below.
Mat4b src= imread("path");
Mat3b dest = imread("path");
Rect roi = Rect(179,539,src.cols,src.rows); //src.cols = 1186 and src.rows= 1134 after scaling.
Mat destinationROI = dest(roi);
src.copyTo(destinationROI);
imwrite("destinationROI.png", destinationROI);
The input src is
The input dest is
But the output got is the same dest image.
Then I tried to save destinationROI befre copying. The output I got is Which is correct one. Copying the src is also working. But it does not make any effect in the dest image.
This is to confirm that #ypnos educated guess was right (nice call, btw).
Take a look at this code, that performs the same operations as yours:
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat4b m4b(50, 50, Vec4b(0, 255, 0, 255)); // blue image, 4 channels
Mat3b m3b(100, 100, Vec3b(255, 0, 0)); // green image, 3 channels
cout << "After init:" << endl;
cout << "m4b channels: " << m4b.channels() << endl;
cout << "m3b channels: " << m3b.channels() << endl << endl;
Rect roi(0, 0, 50, 50); // roi
// Create a new header for the data inside the roi in m3b
// No data copied, just a new header.
// So destRoi has same number of channels of m3b
Mat destRoi = m3b(roi);
cout << "After roi:" << endl;
cout << "m4b channels : " << m4b.channels() << endl;
cout << "m3b channels : " << m3b.channels() << endl;
cout << "destRoi channels: " << destRoi.channels() << endl << endl;
// destination type != source type
// destRoi is newly created with the destination type
// destRoi doesn't point anymore to the data in m3b and has 4 channels now
m4b.copyTo(destRoi);
cout << "After copyTo:" << endl;
cout << "m4b channels : " << m4b.channels() << endl;
cout << "m3b channels : " << m3b.channels() << endl;
cout << "destRoi channels: " << destRoi.channels() << endl << endl;
return 0;
}
Output:
After init:
m4b channels: 4
m3b channels: 3
After roi:
m4b channels : 4
m3b channels : 3
destRoi channels: 3
After copyTo:
m4b channels : 4
m3b channels : 3
destRoi channels: 4
Solution
Use both matrices with same number of channels, either by:
Load both images as 3 channels matrices CV_8UC3. In fact the images you posted are both 3 channels
use cvtColor to convert to the same number of channels, before performing roi and copy operations.
Your matrix types do not match. One has four channels, the other one three.
Obviously, copying the content of a 4-channel matrix into a 3-channel matrix can not work.
Unfortunately in some circumstances OpenCV silently falls back to creating a new matrix when it cannot work on the old memory. Most probably, this is such a case. As soon as you perform the copy, destinationROI starts pointing to new memory.
Note that you might be able to prevent this behavior by declaring destinationROI as Mat3b. To make your code work however, both source and destination need to carry the same number of channels.
Both assumptions I make here are only educated guesses though, I did not test the code in question.
your code is too initial. also your images not suit to a perfect result.guess you performed true code on the images you will get an image of who weared to shirt.
Mat4b src= imread("path");// to load 4 channel image : imread("path",IMREAD_UNCHANGED);
Mat3b dest = imread("path");
Rect roi = Rect(179,539,src.cols,src.rows); //src.cols = 1186 and src.rows= 1134 after scaling.
Mat destinationROI = dest(roi);
src.copyTo(destinationROI);
imwrite("destinationROI.png", destinationROI);
i can write a code to get following image ( it is photoshopped just to show result) but it is meaningless with your images.
EDIT 1 :
i edited your code a bit here. take a look //edit 1,2,3 inside the code.
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>
using namespace cv;
using namespace std;
float sx, sy;
int tx, ty;
struct TaggingPoint{
int rshx, rshy;
int lshx, lshy;
int topx, topy;
int botx, boty;
}body_points, garment_points;
int main(int argc, char** argv)
{
Mat shirt;
Mat body;
shirt = imread(argv[1], IMREAD_COLOR);
if (shirt.empty())
return -1;
body = imread(argv[2], IMREAD_COLOR);
if (body.empty())
return -1;
body_points.rshx = 418;
body_points.rshy = 706;
body_points.lshx = 1234;
body_points.lshy = 706;
body_points.topx = 838;
body_points.topy = 510;
body_points.botx = 838;
body_points.boty = 1534;
garment_points.rshx = 239;
garment_points.rshy = 147;
garment_points.lshx = 755;
garment_points.lshy = 147;
garment_points.topx = 505;
garment_points.topy = 50;
garment_points.botx = 505;
garment_points.boty = 953;
// edit 1 : when you calculate by this values your shirt image's width will be greater that body image's width
// so to reduce it
sx = (float)(body_points.lshx - body_points.rshx) / (garment_points.lshx - garment_points.rshx)*0.995;
sy = (float)(body_points.boty - body_points.topy) / (garment_points.boty - garment_points.topy);
//scale the image
resize(shirt, shirt, Size(), sx, sy, INTER_LINEAR);
imwrite("shirt.png", shirt);
//translation happened
// tx = body_points.rshx - (sx * garment_points.rshx);
tx = body_points.rshx - (garment_points.rshx);
ty = body_points.rshy - (sy * garment_points.rshy);
//draw one image over another image
//src.copyTo(dst.rowRange(1, 6).colRange(3, 10));
// shirt.copyTo(body.rowRange(tx, shirt.rows).colRange(ty, shirt.cols));
// shirt.copyTo(body.rowRange(100, 1000).colRange(100, 500));
// cvtColor(shirt, shirt, CV_BGRA2BGR);
// cvtColor(body, body, CV_BGRA2BGR);
namedWindow("body");
//Rect roi(cv::Point(tx, ty), Size(shirt.size()));
// Edit 2 : Rect.x = 0
Rect roi = Rect(0,ty,shirt.cols,shirt.rows);
Mat destinationROI = body(roi);
// cvtColor(destinationROI, destinationROI, CV_BGRA2BGR);
// Edit 3 : Create a mask ( it is show purpose only, need improvement )
Mat mask;
cvtColor( shirt, mask, COLOR_BGR2GRAY );
mask = mask < 250;
shirt.copyTo(destinationROI,mask);
imwrite("destinationROI.png", destinationROI);
imshow("body", body);
imwrite("body.png", body);
waitKey();
return 0;
}
Related
im beginner in Opencv with c++. I have to draw a filled rectangle(10x10) in the middle of a image where every 5th pixel is black.
i Know how to create a rectangle. But how i can fill it and change the color of every 5th pixel ?
Would be nice if someone can help :/
void cv::rectangle ( InputOutputArray img,
Point pt1,
Point pt2,
const Scalar & color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0
)
My code so far:
#include "opencv2/opencv.hpp"
#include<sstream>
using namespace std;
using namespace cv;
int main(void)
{
//Laden vom Bild
Mat img;
img = imread("C:\\Users\\Mehmet\\Desktop\\yoshi.png");
if (!img.data)
{
cout << "Could not find the image";
return -1;
}
namedWindow("window");
imshow("window", img);
imwrite("C:\\Users\\Max Mustermann\\Desktop\\11.png", img);
cv::Size sz = img.size();
int imageWidth = sz.width;
int imageHeight = sz.height;
cout <<"Es gibt " <<img.channels()<<" Farbkanäle" << endl;;
cout << "Die Breite betreagt: "<<sz.width << endl;
cout <<"Die Hoehe betreagt: " << sz.height<<endl;
std::cout << img.type();
Mat img1;
img.convertTo(img1, CV_32FC3, 1 / 255.0);
waitKey(0);
return 0;
}
```
You may be able to find the answer to your question in the opencv document.
To fill the rectangle, you can change the parameter 'thickness'
==> 'thickness Thickness of lines that make up the rectangle. Negative values, like FILLED, mean that the function has to draw a filled rectangle.'
Link:
https://docs.opencv.org/4.5.2/d6/d6e/group__imgproc__draw.html#ga07d2f74cadcf8e305e810ce8eed13bc9
And, changing color can be done by the color parameter. Controlling this parameter is easy with using cv::Scalar(BLUE, GREEN, RED).
For example, Rectangle(~~~,cv::Scalar(255,0,0),~~~); will make blue colorized rectangle with depending other parameters. So, if you want to change the color, change these values as what you want.
Consequently, if you want to change the color of rectangle repeatably, I think you can surely make the loop with this two parameters.
The complete error:
OpenCV Error: Assertion failed (nimages > 0 && nimages ==
(int)imagePoints1.total() && (!imgPtMat2 || nimages ==
(int)imagePoints2.total())) in collectCalibrationData, file C:\OpenCV
\sources\modules\calib3d\src\calibration.cpp, line 3164
The code:
cv::VideoCapture kalibrowanyPlik; //the video
cv::Mat frame;
cv::Mat testTwo; //undistorted
cv::Mat cameraMatrix = (cv::Mat_<double>(3, 3) << 2673.579, 0, 1310.689, 0, 2673.579, 914.941, 0, 0, 1);
cv::Mat distortMat = (cv::Mat_<double>(1, 4) << -0.208143, 0.235290, 0.001005, 0.001339);
cv::Mat intrinsicMatrix = (cv::Mat_<double>(3, 3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
cv::Mat distortCoeffs = cv::Mat::zeros(8, 1, CV_64F);
//there are two sets for testing purposes. Values for the first two came from GML camera calibration app.
std::vector<cv::Mat> rvecs;
std::vector<cv::Mat> tvecs;
std::vector<std::vector<cv::Point2f> > imagePoints;
std::vector<std::vector<cv::Point3f> > objectPoints;
kalibrowanyPlik.open("625.avi");
//cv::namedWindow("Distorted", CV_WINDOW_AUTOSIZE); //gotta see things
//cv::namedWindow("Undistorted", CV_WINDOW_AUTOSIZE);
int maxFrames = kalibrowanyPlik.get(CV_CAP_PROP_FRAME_COUNT);
int success = 0; //so we can do the calibration only after we've got a bunch
for(int i=0; i<maxFrames-1; i++) {
kalibrowanyPlik.read(frame);
std::vector<cv::Point2f> corners; //creating these here so they're effectively reset each time
std::vector<cv::Point3f> objectCorners;
int sizeX = kalibrowanyPlik.get(CV_CAP_PROP_FRAME_WIDTH); //imageSize
int sizeY = kalibrowanyPlik.get(CV_CAP_PROP_FRAME_HEIGHT);
cv::cvtColor(frame, frame, CV_BGR2GRAY); //must be gray
cv::Size patternsize(9,6); //interior number of corners
bool patternfound = cv::findChessboardCorners(frame, patternsize, corners, cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE + cv::CALIB_CB_FAST_CHECK); //finding them corners
if(patternfound == false) { //gotta know
qDebug() << "failure";
}
if(patternfound) {
qDebug() << "success!";
std::vector<cv::Point3f> objectCorners; //low priority issue - if I don't do this here, it becomes empty. Not sure why.
for(int y=0; y<6; ++y) {
for(int x=0; x<9; ++x) {
objectCorners.push_back(cv::Point3f(x*28,y*28,0)); //filling the array
}
}
cv::cornerSubPix(frame, corners, cv::Size(11, 11), cv::Size(-1, -1),
cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
cv::cvtColor(frame, frame, CV_GRAY2BGR); //I don't want gray lines
imagePoints.push_back(corners); //filling array of arrays with pixel coord array
objectPoints.push_back(objectCorners); //filling array of arrays with real life coord array, or rather copies of the same thing over and over
cout << corners << endl << objectCorners;
cout << endl << objectCorners.size() << "___" << objectPoints.size() << "___" << corners.size() << "___" << imagePoints.size() << endl;
cv::drawChessboardCorners(frame, patternsize, cv::Mat(corners), patternfound); //drawing.
if(success > 5) {
double rms = cv::calibrateCamera(objectPoints, corners, cv::Size(sizeX, sizeY), intrinsicMatrix, distortCoeffs, rvecs, tvecs, cv::CALIB_USE_INTRINSIC_GUESS);
//error - caused by passing CORNERS instead of IMAGEPOINTS. Also, imageSize is 640x480, and I've set the central point to 1310... etc
cout << endl << intrinsicMatrix << endl << distortCoeffs << endl;
cout << "\nrms - " << rms << endl;
}
success = success + 1;
//cv::imshow("Distorted", frame);
//cv::imshow("Undistorted", testTwo);
}
}
I've done a little bit of reading (This was an especially informative read), including over a dozen threads made here on StackOverflow, and all I found is that this error is produced by either by uneven imagePoints and objectPoints or by them being partially null or empty or zero (and links to tutorials that don't help). None of that is the case - the output from .size() check is:
54___7___54___7
For objectCorners (real life coords), objectPoints (number of arrays inserted) and the same for corners (pixel coords) and imagePoints. They're not empty either, the output is:
(...)
277.6792, 208.92903;
241.83429, 208.93048;
206.99866, 208.84637;
(...)
84, 56, 0;
112, 56, 0;
140, 56, 0;
168, 56, 0;
(...)
A sample frame:
I know it's a mess, but so far I'm trying to complete the code rather than get an accurate reading.
Each one hs exactly 54 lines of that. Does anyone have any ideas on what is causing the error? I'm using OpenCV 2.4.8 and Qt Creator 5.4 on Windows 7.
First of all, corners and imagePoints have to be switched, as you have aready noticed.
In most cases (if not all), size <= 25 is enough to get a good result. Focal length around 633 is not wierd, it means the focal length is 633 * sensor size. The CCD or CMOS size must be somewhere on the INSTRUCTIONS along with your camera. Find it out , times 633, the result is your focal length.
One suggestion to reduce the number of images used: using images taken from different viewpoints. 10 images from 10 different viewpoints bring much better result than 100 images from the same ( or nearby ) viewpoints. That is one of the reasons why video is not a good input. I guess with your code, all the images passed to calibratecamera may be from nearby viewpoints. If so, the calibration accuracy degrades.
I'm working on Opencv Project, I'm using C++. I am stuck at computing moving objects distance and speed.
Problem:
I have detected moving cars in video using Haar classifier in Opencv.
But didn't find any way to calculate moving objects
distance from camera as well as moving objects speed.
I want to achieve this using only 1 Camera. I am not using Stereo vision.
Here is my code:
#include <stdio.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>
CvHaarClassifierCascade *cascade;
CvMemStorage *storage;
void detect(IplImage *img);
int main(int argc, char** argv)
{
CvCapture *capture;
IplImage *frame;
int input_resize_percent = 100;
if(argc < 3)
{
std::cout << "Usage " << argv[0] << " cascade.xml video.avi" << std::endl;
return 0;
}
if(argc == 4)
{
input_resize_percent = atoi(argv[3]);
std::cout << "Resizing to: " << input_resize_percent << "%" << std::endl;
}
cascade = (CvHaarClassifierCascade*) cvLoad(argv[1], 0, 0, 0);
storage = cvCreateMemStorage(0);
capture = cvCaptureFromAVI(argv[2]);
assert(cascade && storage && capture);
cvNamedWindow("video", 1);
IplImage* frame1 = cvQueryFrame(capture);
frame = cvCreateImage(cvSize((int)((frame1->width*input_resize_percent)/100) , (int)((frame1->height*input_resize_percent)/100)), frame1->depth, frame1->nChannels);
const int KEY_SPACE = 32;
const int KEY_ESC = 27;
int key = 0;
do
{
frame1 = cvQueryFrame(capture);
if(!frame1)
break;
cvResize(frame1, frame);
detect(frame);
key = cvWaitKey(10);
if(key == KEY_SPACE)
key = cvWaitKey(0);
if(key == KEY_ESC)
break;
}while(1);
cvDestroyAllWindows();
cvReleaseImage(&frame);
cvReleaseCapture(&capture);
cvReleaseHaarClassifierCascade(&cascade);
cvReleaseMemStorage(&storage);
return 0;
}
void detect(IplImage *img)
{
CvSize img_size = cvGetSize(img);
CvSeq *object = cvHaarDetectObjects(
img,
cascade,
storage,
1.1, //1.1,//1.5, //-------------------SCALE FACTOR
1, //2 //------------------MIN NEIGHBOURS
0, //CV_HAAR_DO_CANNY_PRUNING
cvSize(0,0),//cvSize( 30,30), // ------MINSIZE
img_size //cvSize(70,70)//cvSize(640,480) //---------MAXSIZE
);
std::cout << "Total: " << object->total << " cars" << std::endl;
for(int i = 0 ; i < ( object ? object->total : 0 ) ; i++)
{
CvRect *r = (CvRect*)cvGetSeqElem(object, i);
cvRectangle(img,
cvPoint(r->x, r->y),
cvPoint(r->x + r->width, r->y + r->height),
CV_RGB(255, 0, 0), 2, 8, 0);
}
cvShowImage("video", img);
}
If you have any example please provide for better understanding. Its appreciated.
Thanks
I doubt about accuracy, but below mentioned way can help you to find distance of object(moving) to some extent.
Steps:
Find the suitable network to feed your frames for identifying the objects in the video.
Get coordinates of the detections and probably we could find length/area of the detection in further.
Before doing all this, find the focal length of the camera with an object of known size placed at known distance.(Refer Adrian pyimagesearch website).
With known focal length, and the moving object of known size, we can find the distance of the object while moving with the change in area of detected frame.
use this code
I have done it in android
static constexpr int32_t cam_number = 1; /**< The number of the camera, the 0 is the built in my computer. */
static constexpr int32_t cam_width = 640; /**< Width of the video's resolution. */
static constexpr int32_t cam_height = 480; /**< Height of the video's resolution. */
static constexpr int32_t threshold_min = 245; /**< Minimum value of the binary threshold. */
static constexpr int32_t threshold_max = 255; /**< Maximum value of the binary threshold. */
Look-up table for linear interpolation. If you want to make your own version, you have to re-measure these values.
static std::vector<double> pixel = {42.0, 94.0, 122.0, 139.0, 150.0, 157.0, 163.0, 168.0, 171.0}; /**< Measured values of pixels. */
static std::vector<double> cm = {20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0}; /**< Measured values of centimeters. */
/* Initialize the video formats. */
cv::Mat video=srcImg;
cv::Mat video_gray=resultImage;
cv::Mat video_black_white;
try {
/* Vectors for contours and hierarchy. */
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
/* Get a new frame from the camera, convert it to grayscale, then make into black&white with binary threshold. */
cv::cvtColor(video, video_gray, cv::COLOR_RGB2GRAY);
cv::threshold(video_gray, video_black_white, threshold_min, threshold_max,
cv::THRESH_BINARY);
/* Get contours with full hierararchy and simple approximation. */
cv::findContours(video_black_white, contours, hierarchy, cv::RETR_TREE,
cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
/* If there are no contours, skip everything, otherwise there would be an exception. */
if (contours.size()) {
/* Get moments. */
cv::Moments m = cv::moments(contours[0]);
/* Protection from divison by zero. */
if (m.m00 > 0.0) {
/* Calculate the x,y coordinates of the laser point. */
double coord_x = m.m10 / m.m00;
double coord_y = m.m01 / m.m00;
/* Make sure, that we are in the look-up table's range. */
if ((coord_y > pixel[0]) && (coord_y < pixel[pixel.size() - 1])) {
/* Find the place of the coordinate in the look-up table. */
uint32_t i = 0;
while (coord_y > pixel[i + 1]) {
i++;
}
/* Calculate the value with linear interpolation. */
double distance = cm[i] + ((coord_y - pixel[i]) * (cm[i + 1] - cm[i]) /
(pixel[i + 1] - pixel[i]));
dscmm=distance;
std::cout << "X: " << coord_x << "\tY: " << coord_y << "\tDistance: "
// << distance << "\n";
/* Draw a circle on the laser and put a text with the distance on it. */
cv::circle(video, cv::Point(coord_x, coord_y), 5, cv::Scalar(0, 0, 0), 1,
8);
cv::putText(video, std::to_string(distance), cv::Point(coord_x, coord_y),
cv::FONT_HERSHEY_SCRIPT_SIMPLEX, 0.5, cv::Scalar(255, 0, 0), 1);
}
}
}
/* Show the picture. */
/* Press any key to exit. */
}
/* Write out if there is an error. */
catch (std::exception &e) {
LOGD( "JNI:", e.what());
}
I want to implement a background averaging method. I have 50 frames of images taken in one second and some of the frames contain lightning which I want to extract as the foreground. The frames are taken with a stationary camera and the frames are taken as grayscales. What I want to do is:
Get the background model
After, compare each frame to the background model to determine whether there is lighting in that frame or not.
I read some documents on how this can possible be done by using cvAcc() but am having a difficulty understanding how this can be done. I would appreciate a piece of code which guide me and links to documents that can help me understand how I can implement this.
Thanking you in advance.
We had the same task in one of our projects.
To get the background model, we simply create a class BackgroundModel, capture the first (lets say) 50 frames and calculate the average frame to avoid pixel errors in the background model.
For example, if you get an 8-bit greyscale image (CV_8UC1) from your camera, you initialize your model with CV_16UC1 to avoid clipping.
cv::Mat model = cv::Mat(HEIGHT, WIDTH, CV_16UC1, cv::Scalar(0));
Now, waiting for the first frames to calculate your model, just add every frame to the model and count the amount of received frames.
void addFrame(cv::Mat frame) {
cv::Mat convertedFrame;
frame.convertTo(convertedFrame, CV_16UC1);
cv::add(convertedFrame, model, model);
if (++learnedFrames >= FRAMES_TO_LEAN) { // FRAMES_TO_LEARN = 50
createMask();
}
}
The createMask() function calculates the average frame which we use for the model.
void createMask() {
cv::convertScaleAbs(model, mask, 1.0 / learnedFrames);
mask.convertTo(mask, CV_8UC1);
}
Now, you just send all the frames the way through the BackgroundModel class to a function subtract(). If the result is an empty cv::Mat, the mask is still calculated. Otherwise, you get a subtracted frame.
cv::Mat subtract(cv::Mat frame) {
cv::Mat result;
if (++learnedFrames >= FRAMES_TO_LEAN) { // FRAMES_TO_LEARN = 50
cv::subtract(frame, mask, result);
}
else {
addFrame(frame);
}
return result;
}
Last but not least, you can use
Scalar sum(const Mat& mtx)
to calculate the pixel sum and decide if it's a frame with lights on it.
MyPolygon function mask the ROI and after that, it calculates the abs Pixel difference and calculates the number of white pixels.
srcImage : Reference image.
#include <opencv2/opencv.hpp>
#include <iostream>
#include <random>
using namespace std;
using namespace cv;
cv::Mat MyPolygon( Mat img )
{
int lineType = 8;
// [(892, 145), (965, 150), (933, 199), (935, 238), (970, 248), (1219, 715), (836, 709), (864, 204)]
/** Create some points */
Point rook_points[1][8];
rook_points[0][0] = Point(892, 145);
rook_points[0][1] = Point(965, 150);
rook_points[0][2] = Point(933, 199);
rook_points[0][3] = Point(935, 238);
rook_points[0][4] = Point(970, 248);
rook_points[0][5] = Point(1219, 715);
rook_points[0][6] = Point(836, 709);
rook_points[0][7] = Point(864, 204);
const Point* ppt[1] = { rook_points[0] };
int npt[] = { 8 };
cv::Mat mask = cv::Mat::zeros(img.size(), img.type());
fillPoly( mask,
ppt,
npt,
1,
Scalar( 255, 0, 0 ),
lineType
);
cv::bitwise_and(mask,img, img);
return img;
}
int main() {
/* code */
cv::Mat srcImage = cv::imread("/home/gourav/Pictures/L1 Image.png", cv::IMREAD_GRAYSCALE);
resize(srcImage, srcImage, Size(1280, 720));
// cout << " Width : " << srcImage.cols << endl;
// cout << " Height: " << srcImage.rows << endl;
if (srcImage.empty()){
std::cerr<<"Ref Image not found\n";
return 1;
}
cv::Mat img = MyPolygon(srcImage);
Mat grayBlur;
GaussianBlur(srcImage, grayBlur, Size(5, 5), 0);
VideoCapture cap("/home/gourav/GenralCode/LD3LF1_stream1.mp4");
Mat frames;
if(!cap.isOpened()){
std::cout << "Error opening video stream or file" << endl;
return -1;
}
while (1)
{
cap >> frames;
if (frames.empty())
break;
// Convert current frame to grayscale
cvtColor(frames, frames, COLOR_BGR2GRAY);
// cout << "Frame Width : " << frames.cols << endl;
// cout << "Frame Height: " << frames.rows << endl;
Mat imageBlure;
GaussianBlur(frames, imageBlure, Size(5, 5), 0);
cv::Mat frame = MyPolygon(imageBlure);
Mat dframe;
absdiff(frame, grayBlur, dframe);
// imshow("grayBlur", grayBlur);
// Threshold to binarize
threshold(dframe, dframe, 30, 255, THRESH_BINARY);
//White Pixels
int number = cv::countNonZero(dframe);
cout<<"Count: "<< number <<"\n";
if (number > 3000)
{
cout<<"generate Alert ";
}
// Display Image
imshow("dframe", dframe);
char c=(char)waitKey(25);
if (c==27)
break;
}
cap.release();
return 0;
}
I have a function that I would like to apply to each pixel in a YUN image (call it src). I would like the output to be saved to a separate image, call it (dst).
I know I can achieve this through pointer arithmetic and accessing the underlying matrix of the image. I was wondering if there was a easier way, say a predefined "map" function that allows me to map a function to all the pixels?
Thanks,
Since I don't know what a YUN image is, I'll assume you know how to convert RGB to that format.
I'm not aware of an easy way to do the map function you mentioned. Anyway, OpenCV has a few predefined functions to do image conversion, including
cvCvtColor(color_frame, gray_frame, CV_BGR2GRAY);
which you might want to take a closer look.
If you would like to do your own, you would need to access each pixel of the image individually, and this code shows you how to do it (the code below skips all kinds of error and return checks for the sake of simplicity):
// Loading src image
IplImage* src_img = cvLoadImage("input.png", CV_LOAD_IMAGE_UNCHANGED);
int width = src_img->width;
int height = src_img->height;
int bpp = src_img->nChannels;
// Temporary buffer to save the modified image
char* buff = new char[width * height * bpp];
// Loop to iterate over each pixel of the original img
for (int i=0; i < width*height*bpp; i+=bpp)
{
/* Perform pixel operation inside this loop */
if (!(i % (width*bpp))) // printing empty line for better readability
std::cout << std::endl;
std::cout << std::dec << "R:" << (int) src_img->imageData[i] <<
" G:" << (int) src_img->imageData[i+1] <<
" B:" << (int) src_img->imageData[i+2] << " ";
/* Let's say you wanted to do a lazy grayscale conversion */
char gray = (src_img->imageData[i] + src_img->imageData[i+1] + src_img->imageData[i+2]) / 3;
buff[i] = gray;
buff[i+1] = gray;
buff[i+2] = gray;
}
IplImage* dst_img = cvCreateImage(cvSize(width, height), src_img->depth, bpp);
dst_img->imageData = buff;
if (!cvSaveImage("output.png", dst_img))
{
std::cout << "ERROR: Failed cvSaveImage" << std::endl;
}
Basically, the code loads a RGB image from the hard disk and performs a grayscale conversion on each pixel of the image, saving it to a temporary buffer. Later, it will create another IplImage with the grayscale data and then it will save it to a file on the disk.