For now I have:
Mat avgImg(480, 640, CV_32FC3, Scalar()); // Create and zero initialize
Mat capturedImg;
for (framenumb = 0; framenumb < 10; ++framenumb)
{
// avgImg.create(480, 640, CV_32FC3); // Don't create each time!
capturedImg = images[framenumb];
cv::accumulate(capturedImg, avgImg);
}
avgImg = avgImg / 100;
avgImg.convertTo(avgImg, CV_8UC3);
imshow("averaged", avgImg);
How can I make it so that the forloop values will increase every time it finishes looping. For example, after 10 images are accumulated and averaged, the loop will then automatically change to for (framenumb = 10; framenumb < 20; ++framenumb)to take the next 10 images and so on.
Something as simple as:
for(int i = 0; i < NUM; i++) {
Mat avgImg(480, 640, CV_32FC3, Scalar()); // Create and zero initialize
Mat capturedImg;
for (framenumb = 10 * i; framenumb < (10 * i) + 10; ++framenumb) {
// avgImg.create(480, 640, CV_32FC3); // Don't create each time!
capturedImg = images[framenumb];
cv::accumulate(capturedImg, avgImg);
}
avgImg = avgImg / 100;
avgImg.convertTo(avgImg, CV_8UC3);
imshow("averaged", avgImg);
}
Where NUM is the number of images divided by 10.
Related
the code posted below shows an implementation of a Richard-Lucy deconvolution, which is supposed to recover a blurred image using the point spread function. I found this on GitHub (RL_deconv/rl_deconv.cpp at master · chrrrisw/RL_deconv · GitHub) and it was a good starting point for my problem. The input given is a 3D image and a 2D PSF.
As I said before, this program only works with 2D psf images, but I would to do this with a 3D psf. My research for a 3D filter was unfortunately without result.
My question now is whether there is a 3D filter in OpenCV or is there another approach for this task?
I would appreciate any help.
#define _USE_MATH_DEFINES
#include "opencv2/opencv.hpp"
#include <iostream>
#include <cmath>
using namespace cv;
using namespace std;
// From wikipedia:
//
// def RL_deconvolution(observed, psf, iterations):
// # initial estimate is arbitrary - uniform 50% grey works fine
// latent_est = 0.5*np.ones(observed.shape)
// # create an inverse psf
// psf_hat = psf[::-1,::-1]
// # iterate towards ML estimate for the latent image
// for i in np.arange(iterations):
// est_conv = cv2.filter2D(latent_est,-1,psf)
// relative_blur = observed/est_conv;
// error_est = cv2.filter2D(relative_blur,-1,psf_hat)
// latent_est = latent_est * error_est
// return latent_est
static int image_type;
Mat RL_deconvolution(Mat observed, Mat psf, int iterations) {
Scalar grey;
// Uniform grey starting estimation
switch (image_type) {
case CV_64FC1:
grey = Scalar(0.5);
case CV_64FC3:
grey = Scalar(0.5, 0.5, 0.5);
}
Mat latent_est = Mat(observed.size(), image_type, grey);
// Flip the point spread function (NOT the inverse)
Mat psf_hat = Mat(psf.size(), CV_64FC1);
int psf_row_max = psf.rows - 1;
int psf_col_max = psf.cols - 1;
for (int row = 0; row <= psf_row_max; row++) {
for (int col = 0; col <= psf_col_max; col++) {
psf_hat.at<double>(psf_row_max - row, psf_col_max - col) =
psf.at<double>(row, col);
}
}
Mat est_conv;
Mat relative_blur;
Mat error_est;
// Iterate
for (int i = 0; i < iterations; i++) {
filter2D(latent_est, est_conv, -1, psf);
// Element-wise division
relative_blur = observed.mul(1.0 / est_conv);
filter2D(relative_blur, error_est, -1, psf_hat);
// Element-wise multiplication
latent_est = latent_est.mul(error_est);
}
return latent_est;
}
int main(/*int argc, const char** argv*/)
{
//if (argc != 3) {
// cout << "Usage: " << argv[0] << " image iterations" << "\n";
// return -1;
//}
//int iterations = atoi(argv[2]);
int iterations = 10;
// Read the original image
Mat original_image;
//original_image = imread(argv[1], IMREAD_UNCHANGED); //CV_LOAD_IMAGE_UNCHANGED is replaced by IMREAD_UNCHANGED
original_image = imread("myosin.tif", IMREAD_UNCHANGED); //CV_LOAD_IMAGE_UNCHANGED is replaced by IMREAD_UNCHANGED
int num_channels = original_image.channels();
switch (num_channels) {
case 1:
image_type = CV_64FC1;
break;
case 3:
image_type = CV_64FC3;
break;
default:
return -2;
}
// This is a hack, assumes too much
int divisor;
switch (original_image.elemSize() / num_channels) {
case 1:
divisor = 255;
break;
case 2:
divisor = 65535;
break;
default:
return -3;
}
// From here on, use 64-bit floats
// Convert original_image to float
Mat float_image;
original_image.convertTo(float_image, image_type);
float_image *= 1.0 / divisor;
namedWindow("Float", WINDOW_AUTOSIZE); // CV_WINDOW_AUTOSIZE replaced with WINDOW_AUTOSIZE
imshow("Float", float_image);
// Calculate a gaussian blur psf.
double sigma_row = 9.0;
double sigma_col = 5.0;
int psf_size = 5;
double mean_row = 0.0;
double mean_col = psf_size / 2.0;
double sum = 0.0;
double temp;
Mat psf = Mat(Size(psf_size, psf_size), CV_64FC1, 0.0);
for (int j = 0; j < psf.rows; j++) {
for (int k = 0; k < psf.cols; k++) {
temp = exp(
-0.5 * (
pow((j - mean_row) / sigma_row, 2.0) +
pow((k - mean_col) / sigma_col, 2.0))) /
(2 * M_PI * sigma_row * sigma_col);
sum += temp;
psf.at<double>(j, k) = temp;
}
}
// Normalise the psf.
for (int row = 0; row < psf.rows; row++) {
// cout << row << " ";
for (int col = 0; col < psf.cols; col++) {
psf.at<double>(row, col) /= sum;
// cout << psf.at<double>(row, col) << " ";
}
// cout << "\n";
}
//Mat psf;
////original_image = imread(argv[1], IMREAD_UNCHANGED); //CV_LOAD_IMAGE_UNCHANGED is replaced by IMREAD_UNCHANGED
//psf = imread("E:/PSF_GL.tif", IMREAD_UNCHANGED);
// Blur the float_image with the psf.
Mat blurred_float;
blurred_float = float_image.clone();
filter2D(float_image, blurred_float, -1, psf);
namedWindow("BlurredFloat", WINDOW_AUTOSIZE); // CV_WINDOW_AUTOSIZE replaced with WINDOW_AUTOSIZE
imshow("BlurredFloat", blurred_float);
Mat estimation = RL_deconvolution(blurred_float, psf, iterations);
namedWindow("Estimation", WINDOW_AUTOSIZE); // CV_WINDOW_AUTOSIZE replaced with WINDOW_AUTOSIZE
imshow("Estimation", estimation);
waitKey(0); //wait infinite time for a keypress
destroyWindow("Float");
destroyWindow("BlurredFloat");
destroyWindow("Estimation");
return 0;
}
Sadly I didn't found any combarable solution, but I hope anybody can help me.
I have 2 transparent images which I want them to be opened in one window in opencv.
The code below opens two images but with out alpha channel because it's using (CV_8UC3) and those images which are transparent we should use (CV_8UC4) to show the transparency but when I change the code to (CV_8UC4) the program gives me an error.
I'll put a # on the line of (CV_8UC4);
I'll put a * on the line of error;
//the code turned to 3 parts because of * and #.
Is this code suitable for what I want to do?
This code opens multiple images but i've use it for two.
code is:
void ShowManyImages(string title, int nArgs, ...) {
int size;
int i;
int m, n;
int x, y;
// w - Maximum number of images in a row
// h - Maximum number of images in a column
int w, h;
// scale - How much we have to resize the image
float scale;
int max;
// If the number of arguments is lesser than 0 or greater than 12
// return without displaying
if (nArgs <= 0) {
printf("Number of arguments too small....\n");
return;
}
else if (nArgs > 14) {
printf("Number of arguments too large, can only handle maximally 12 images at a time ...\n");
return;
}
// Determine the size of the image,
// and the number of rows/cols
// from number of arguments
else if (nArgs == 1) {
w = h = 1;
size = 300;
}
else if (nArgs == 2) {
w = 2; h = 1;
size = 1000;
}
else if (nArgs == 3 || nArgs == 4) {
w = 2; h = 2;
size = 300;
}
else if (nArgs == 5 || nArgs == 6) {
w = 3; h = 2;
size = 200;
}
else if (nArgs == 7 || nArgs == 8) {
w = 4; h = 2;
size = 200;
}
else {
w = 4; h = 3;
size = 150;
}
// Create a new 3 channel image
# Mat DispImage = Mat::zeros(Size(100 + size*w, 60 + size*h), CV_8UC4);
// Used to get the arguments passed
va_list args;
va_start(args, nArgs);
// Loop for nArgs number of arguments
for (i = 0, m = 20, n = 20; i < nArgs; i++, m += (0)) {
// Get the Pointer to the IplImage
Mat img = va_arg(args, Mat);
// Check whether it is NULL or not
// If it is NULL, release the image, and return
if (img.empty()) {
printf("Invalid arguments");
return;
}
// Find the width and height of the image
x = img.cols;
y = img.rows;
// Find whether height or width is greater in order to resize the image
max = (x > y) ? x : y;
// Find the scaling factor to resize the image
scale = (float)((float)max / size);
// Used to Align the images
if (i % w == 0 && m != 20) {
m = 20;
n += 20 + size;
}
// Set the image ROI to display the current image
// Resize the input image and copy the it to the Single Big Image
Rect ROI(m, n, (int)(x / scale), (int)(y / scale));
Mat temp; resize(img, temp, Size(ROI.width, ROI.height));
* temp.copyTo(DispImage(ROI));
}
// Create a new window, and show the Single Big Image
namedWindow(title, 1);
imshow(title, DispImage);
waitKey();
// End the number of arguments
va_end(args);
}
int main(int argc, char** argv)
{
Mat img1 = imread("c:\\1.png");
Mat img2 = imread("c:\\2.png");
ShowManyImages("Image", 2, img1, img2);
return 0;
}
I want to use connected component algorithm for object detection.I can use this algorithm on full image but I want to implementation connected component for a part of image.for example the size of my image is 760*520 and I want to implementation this algorithm on a square with size (350,270,60,60).this is a part of my code: `Mat image;
Mat stat, centroid;
int threshval = 100;
static void on_trackbar(int, void*) {
Mat bw = threshval < 128 ? (image < threshval) : (image > threshval);
Mat labelImage(image.size(), CV_32S);
int nLabels = connectedComponentsWithStats(bw, labelImage, stat, centroid, 8);
std::vector<Vec3b> colors(nLabels);
colors[0] = Vec3b(0, 0, 0); // Background
for (int label = 1; label < nLabels; ++label) {
colors[label] = Vec3b((rand() & 255), (rand() & 255), (rand() & 255));
at dst(image.size(), CV_8UC3);
for (int r = 0; r < dst.rows; ++r) {
for (int c = 0; c < dst.cols; ++c) {
int label = labelImage.at<int>(r, c);
Vec3b &pixel = dst.at<Vec3b>(r, c);
pixel = colors[label];
}
imshow("Connected Components", dst);
}
}
}
Except use image(cv::Rect(350, 270, 60, 60)) Instead of** image**,do you have any idea to help me?I'm beginner in opencv and c++.thanks a lot...
I first used this code to capture webcam frames:
int main(int argc, char** argv)
{
VideoCapture cap(0); // open the default camera
if (!cap.isOpened()) // check if we succeeded
return -1;
cap.set(CV_CAP_PROP_FPS, 15);
std::vector<cv::Mat> images(100);
for (framenumb = 0; framenumb < 100; ++framenumb)
{
// this is optional, preallocation so there's no allocation
// during capture
images[framenumb].create(480, 640, CV_32FC3);
}
for (framenumb = 0; framenumb < 100; ++framenumb)
{
Mat frame;
cap >> frame;
if (frame.empty()) break; // end of video stream
imshow("webcam", frame);
if (waitKey(1) == 27) break; // stop capturing by pressing ESC
frame.copyTo(images[framenumb]);
}
and then tried to use the following code to average the captured frames:
Mat avgImg;
Mat capturedImg;
for (framenumb = 0; framenumb < 100; ++framenumb)
{
avgImg.create(480, 640, CV_32FC3);
capturedImg = images[framenumb];
cv::accumulate(capturedImg, avgImg);
}
avgImg = avgImg / 100;
avgImg.convertTo(avgImg, CV_8UC3);
imshow("averaged", avgImg);
But then it just broke the programme and gave me a black image. Can anyone help me to identify where the error is? Thank you very much
You need to:
Create a zero initialized accumulation image
Add every image to it
Divide the accumulated image by the number of images
You instead re-create an empty accumulation image at every frame.
The code should be changed as:
Mat avgImg(480, 640, CV_32FC3, Scalar()); // Create and zero initialize
Mat capturedImg;
for (framenumb = 0; framenumb < 100; ++framenumb)
{
// avgImg.create(480, 640, CV_32FC3); // Don't create each time!
capturedImg = images[framenumb];
cv::accumulate(capturedImg, avgImg);
}
You probably can simplify your code as:
Mat avgImg(480, 640, CV_32FC3, Scalar()); // Create and zero initialize
for (framenumb = 0; framenumb < 100; ++framenumb)
{
avgImg += images[framenumb];
}
I have an image 800x800 which is broken down to 16 blocks of 200x200.
(you can see previous post here)
These blocks are : vector<Mat> subImages;
I want to use float pointers on them , so I am doing :
float *pdata = (float*)( subImages[ idxSubImage ].data );
1) Now, I want to be able to get again the same images/blocks, going from float array to Mat data.
int Idx = 0;
pdata = (float*)( subImages[ Idx ].data );
namedWindow( "Display window", WINDOW_AUTOSIZE );
for( int i = 0; i < OriginalImgSize.height - 4; i+= 200 )
{
for( int j = 0; j < OriginalImgSize.width - 4; j+= 200, Idx++ )
{
Mat mf( i,j, CV_32F, pdata + 200 );
imshow( "Display window", mf );
waitKey(0);
}
}
So , the problem is that I am receiving an
OpenCV Error: Assertion failed
in imshow.
2) How can I recombine all the blocks to obtain the original 800x800 image?
I tried something like:
int Idx = 0;
pdata = (float*)( subImages[ Idx ].data );
Mat big( 800,800,CV_32F );
for( int i = 0; i < OriginalImgSize.height - 4; i+= 200 )
{
for( int j = 0; j < OriginalImgSize.width - 4; j+= 200, Idx++ )
{
Mat mf( i,j, CV_32F, pdata + 200 );
Rect roi(j,i,200,200);
mf.copyTo( big(roi) );
}
}
imwrite( "testing" , big );
This gives me :
OpenCV Error: Assertion failed (!fixedSize()) in release
in mf.copyTo( big(roi) );.
First, you need to know where are your subimages into the big image. To do this, you can save the rect of each subimage into the vector<Rect> smallImageRois;
Then you can use pointers (keep in mind that subimages are not continuous), or simply use copyTo to the correct place:
Have a look:
#include <opencv2\opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
Mat3b img = imread("path_to_image");
resize(img, img, Size(800, 800));
Mat grayImg;
cvtColor(img, grayImg, COLOR_BGR2GRAY);
grayImg.convertTo(grayImg, CV_32F);
int N = 4;
if (((grayImg.rows % N) != 0) || ((grayImg.cols % N) != 0))
{
// Error
return -1;
}
Size graySize = grayImg.size();
Size smallSize(grayImg.cols / N, grayImg.rows / N);
vector<Mat> smallImages;
vector<Rect> smallImageRois;
for (int i = 0; i < graySize.height; i += smallSize.height)
{
for (int j = 0; j < graySize.width; j += smallSize.width)
{
Rect rect = Rect(j, i, smallSize.width, smallSize.height);
smallImages.push_back(grayImg(rect));
smallImageRois.push_back(rect);
}
}
// Option 1. Using pointer to subimage data.
Mat big1(800, 800, CV_32F);
int big1step = big1.step1();
float* pbig1 = big1.ptr<float>(0);
for (int idx = 0; idx < smallImages.size(); ++idx)
{
float* pdata = (float*)smallImages[idx].data;
int step = smallImages[idx].step1();
Rect roi = smallImageRois[idx];
for (int i = 0; i < smallSize.height; ++i)
{
for (int j = 0; j < smallSize.width; ++j)
{
pbig1[(roi.y + i) * big1step + (roi.x + j)] = pdata[i * step + j];
}
}
}
// Option 2. USing copyTo
Mat big2(800, 800, CV_32F);
for (int idx = 0; idx < smallImages.size(); ++idx)
{
smallImages[idx].copyTo(big2(smallImageRois[idx]));
}
return 0;
}
For concatenating the sub-images into a single squared image, you can use the following function:
// Important: all patches should have exactly the same size
Mat concatPatches(vector<Mat> &patches) {
assert(patches.size() > 0);
// make it square
const int patch_width = patches[0].cols;
const int patch_height = patches[0].rows;
const int patch_stride = ceil(sqrt(patches.size()));
Mat image = Mat::zeros(patch_stride * patch_height, patch_stride * patch_width, patches[0].type());
for (size_t i = 0, iend = patches.size(); i < iend; i++) {
Mat &patch = patches[i];
const int offset_x = (i % patch_stride) * patch_width;
const int offset_y = (i / patch_stride) * patch_height;
// copy the patch to the output image
patch.copyTo(image(Rect(offset_x, offset_y, patch_width, patch_height)));
}
return image;
}
It takes a vector of sub-images (or patches as I refer them to) and concatenates them into a squared image. Example usage:
vector<Mat> patches;
vector<Scalar> colours = {Scalar(255, 0, 0), Scalar(0, 255, 0), Scalar(0, 0, 255)};
// fill vector with circles of different colours
for(int i = 0; i < 16; i++) {
Mat patch = Mat::zeros(100,100, CV_32FC3);
circle(patch, Point(50,50), 40, colours[i % 3], -1);
patches.push_back(patch);
}
Mat img = concatPatches(patches);
imshow("img", img);
waitKey();
Will produce the following image
print the values of i and j before creating Mat mf and I believe you will soon be able to find the error.
Hint 1: i and j will be 0 the first time
Hint 2: Use the copyTo() with a ROI like:
cv::Rect roi(0,0,200,200);
src.copyTo(dst(roi))
Edit:
Hint 3: Try not to do such pointer fiddling, you will get in trouble. Especially if you're ignoring the step (like you seem to do).