How to convolve using for loops in opencv c++? [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 days ago.
Improve this question
I am not getting proper output with current data types in the program.
I am getting a very undesired and unexpectedly large values while accessing each element as well
#include <opencv2/opencv.hpp>
#include <iostream>
/*
Specifying Namespaces
Namespace is a declarative region that provides a scope to the identifiers (the names of types, functions, variables, etc) inside it.
*/
using namespace std;
using namespace cv;
/// #brief : Convolution will help apply different kernels to your images yielding different results
/// #param Original_image
/// #param kernel
/// #return : An Output Image with the kernel applied
Mat convolve(Mat kernel, Mat original_image){
Mat kernel_inv;
Mat resultant_image{original_image.size(), original_image.type()};
// Just checking whether these funcitons are continuous or not
kernel_inv.isContinuous();
kernel.isContinuous();
// ################################ Flip Kernel Suboptimally ######################## //
// Method 2: Simply using in-built functions
flip(kernel, kernel_inv, -1);
// #################################################################################### //
for (int i = 1; i < original_image.rows; i++)
{
for (int j = 1; j < original_image.cols; j++)
{
double tmp = 0.0;
for (int k = 0; k < kernel_inv.rows; k++)
{
for (int l = 0; l < kernel_inv.cols; l++)
{
int x = j - 1 + l;
int y = i - 1 + k;
if ((x >= 0 && x < original_image.cols) && (y >= 0 && y < original_image.rows)){
tmp += (int)original_image.at<u_char>(y, x) * (int)kernel_inv.at<u_char>(k, l);
}
}
}
resultant_image.at<u_char>(i, j) = saturate_cast<char>(tmp);
}
}
return resultant_image;
}
int main( int argc, char** argv )
{
Mat image = imread("../dog_test.png",IMREAD_GRAYSCALE); // Read Image
Mat img2;
// Format for last argument in Create, ones and zero
// CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
/*
// Try These Lines by uncommenting the code one by one
// kernel.create(4,4, CV_8UC(2)); // Just to create a matrix
// kernel = Mat::ones(4,4, CV_64F); // Just to create matrix with all entries 1
// kernel = Mat::eye(4,4, CV_32F); // Just to create matrix with all entries 0
*/
double sobelx_data[9] = {0.111, 0.111, 0.111, 0.111, 0.111, 0.111, 0.111, 0.111, 0.111};
Mat sobelx = cv::Mat(3, 3, CV_32F, sobelx_data);
// cout<<image<<endl<<endl;
img2 = convolve(sobelx, image);
cout<<"Original: "<<(int)image.at<u_char>(100,250)<<endl;
cout<<"img2: "<<(int)img2.at<u_char>(100,250)<<endl;
// cout<<"OUTPUT = \n"<<img2<<endl<<endl;
// Functions to show images
namedWindow("Copy", WINDOW_NORMAL);
imshow("Copy", img2);
// Resizing the Window for Better Visualization
waitKey(0);
return 0;
}
I have tried to access the elements using .at attribute in cv mat, which gives arbitrary values, so another problem is how to determine the type of the elements used in the matrix
So, this was the method that I tried, so if anyone can help me it will be great.

Related

How to parallelize/optimize for loops in a Rank Transform of an image?

I want to speed up the rank transform of an image using
#pragma omp parallel for
The rank transform is actually similar to a filter operation and I implemented it using nested for loops. The performance of the rank transform of a 1200x1200 image is unchanged and takes about 9.68 s for various #pragma operators.
I tested several configurations from https://bisqwit.iki.fi/story/howto/openmp/.
The pragma operator in the code sample below has no effect. It marks the part that should be parallelized.
Any ideas how to apply the #pragma operators correctly to have an effect?
System:
Windows 10 x64, Visual Studio 2019 - Microsoft Visual C++ (MSVC),
Intel(R) Core(TM) i7-7700K CPU # 4.20GHz
#include <iostream>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <omp.h>
using namespace std;
using namespace cv;
// cv::Mat class is used
Mat rank_transform(Mat image, int windowsize)
{
// input: CV_8UC1 Mat, padded image with zeros ( borderwidth of padding -> int halfWindow = windowSize/2; )
// output: CV_8UC1 Mat, unpadded rank transformed image
//
// TO DO: add try..catch modulo 2 of windows size and add one onto the window size when number is even
int halfWindow = windowsize / 2;
// iterate over the padded image
int rows = image.rows;
int cols = image.cols;
// only return the true parts of the image without padded values, returned image
Mat rankImage = Mat(image.rows - 2 * halfWindow, image.cols - 2 * halfWindow, CV_8UC1);
// center pixel position (v, u) starts at half window size
// and iterates over all rows as long as row < (totalRows - halfWindow)
#pragma omp parallel for
for (int v = halfWindow; v < rows - halfWindow; v++)
{
for (int u = halfWindow; u < cols - halfWindow; u++)
{
// initialize rank score
int score = 0;
// iterate through the neighboring pixels of a window
for (int vWin = -halfWindow; vWin <= halfWindow; vWin++)
{
for (int uWin = -halfWindow; uWin <= halfWindow; uWin++)
{
// if neighbor has a higher intensity than the center pixel, access (row, column)
if (image.at<uchar>(v + vWin, u + uWin) > image.at<uchar>(v, u))
score++;
}
}
// access (row, column), write score
rankImage.at<uchar>(v - halfWindow, u - halfWindow) = score;
}
}
return rankImage;
}
Update: After adjusting my Settings in Visual Studio 2019, the code and performing a system restart, I get for a 8UC1 1214x1214 Mat and a window size of 15x15 an elapsed time of 2.65707 s.
Any suggestions for further improvement?

Calculate 1DPlot, determine the maxima and their distances between each other

I want to create a 1D plot from an image. Then I want to determine the maxima and their distances to each other in c++.
I am looking for some tips on how I could approach this.
I load the image as cv::Mat. In opencv I have searched, but only found the histogram function, which is wrong. I want to get a cross section of the image - from left to right.
does anyone have an idea ?
Well I have the following picture:
From this I want to create a 1D plot like in the following picture (I created the plot in ImageJ).
Here you can see the maxima (I could refine it with "smooth").
I want to determine the positions of these maxima and then the distances between them.
I have to get to the 1D plot somehow. I suppose I can get to the maxima with a derivation?
++++++++++ UPDATE ++++++++++
Now i wrote this to get an 1D Plot:
cv::Mat img= cv::imread(imgFile.toStdString(), cv::IMREAD_ANYDEPTH | cv::IMREAD_COLOR);
cv::cvtColor(img, img, cv::COLOR_BGR2GRAY);
uint8_t* data = img.data;
int width = img.cols;
int height = img.rows;
int stride = img.step;
std::vector<double> vPlot(width, 0);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
uint8_t val = data[ i * stride + j];
vPlot[j]=vPlot[j] + val;
}
}
std::ofstream file;
file.open("path\\plot.csv");
for(int i = 0; i < vPlot.size(); i++){
file << vPlot[i];
file << ";";
}
file.close();
When i plot this in excel i got this:
Thats looks not so smooth as in ImageJ. Did i something wrong?
I need it like in the Plot of ImageJ - more smooth.
ok I got it:
for (int i = 0; i < vPlot.size(); i++) {
vPlot[i] = vPlot[i] / height;
}
Ok but i don't know how to get the maxima an distances.
When i have the local maxima (i don't know how), i can calculate the distance between them with the index of the vetcor elements.
Has anybody an idea to get the local Maxima out of the vector, that I plot above ?
Now o wrote this to find the maxima:
// find maxima
std::vector<int> idxMax;
int flag = 0;
for(int i = 1; i < avg.size(); i++){
double diff = avg[i] - avg[i-1];
if(diff < 0){
if(flag>0){
idxMax.push_back(i);
flag = -1;
}
}
if(diff >= 0){
if(flag<=0){
flag = 1;
}
}
}
But more maxima are found than wanted. The length of the vector varies and also the number of peaks. These can be close together or far away. They are also not always the same height, as can be seen in the picture

How does the return value "res" is updated? (ConcativeMat Con NN)

I have a questions about a for loop and its return value. This is C++ code, and I'm using openCV 2.4V.
Input to this function is max value of 600 images with pooling.
600 images << pooling << max value points.
The size of "res" matrix is 600x128 and vec.size() = 600.
For me, within the for loop, the res never get updated, however return value is not zeros.
I suspected
"ptmat.copyTo(subView)"
because, I thought that is not necessary line. However when I took that out, res did not get updated(being zero like initial Mat). Can anybody explain how does the res value get updated?
Also why does this function is called concatenate..?
Mat
concatenateMat(vector<vector<Mat> > &vec) {
int subFeatures = vec[0][0].rows * vec[0][0].cols;
int height = vec[0].size() * subFeatures;
int width = vec.size();
Mat res = Mat::zeros(height, width, CV_64FC1);
for (int i = 0; i<vec.size(); i++) {
for (int j = 0; j<vec[i].size(); j++) {
Rect roi = Rect(i, j * subFeatures, 1, subFeatures);
Mat subView = res(roi);
Mat ptmat = vec[i][j].reshape(0, subFeatures);
ptmat.copyTo(subView);
}
}
return res;
}
According to OpenCV documentation, the Mat::operator() does not make a copy of matrix data, thus any change to subView matrix object in the loop will be reflected in res matrix object as well. That's the line you've mentioned:
ptmat.copyTo(subView);
It's called concatenate because it concatenates 2D vector of Mat objects into a single one.

OpenCV VLFeat Slic function call

I am trying to use the vl_slic_segment function of the VLFeat library using an input image stored in an OpenCV Mat. My code is compiling and running, but the output superpixel values do not make sense. Here is my code so far :
Mat bgrUChar = imread("/pathtowherever/image.jpg");
Mat bgrFloat;
bgrUChar.convertTo(bgrFloat, CV_32FC3, 1.0/255);
cv::Mat labFloat;
cvtColor(bgrFloat, labFloat, CV_BGR2Lab);
Mat labels(labFloat.size(), CV_32SC1);
vl_slic_segment(labels.ptr<vl_uint32>(),labFloat.ptr<const float>(),labFloat.cols,labFloat.rows,labFloat.channels(),30,0.1,25);
I have tried not converting it to the Lab colorspace and setting different regionSize/regularization, but the output is always very glitchy. I am able to retrieve the label values correctly, the thing is the every labels is usually scattered on a little non-contiguous area.
I think the problem is the format of my input data is wrong but I can't figure out how to send it properly to the vl_slic_segment function.
Thank you in advance!
EDIT
Thank you David, as you helped me understand, vl_slic_segment wants data ordered as [LLLLLAAAAABBBBB] whereas OpenCV is ordering its data [LABLABLABLABLAB] for the LAB color space.
In the course of my bachelor thesis I have to use VLFeat's SLIC implementation as well. You can find a short example applying VLFeat's SLIC on Lenna.png on GitHub: https://github.com/davidstutz/vlfeat-slic-example.
Maybe, a look at main.cpp will help you figuring out how to convert the images obtained by OpenCV to the right format:
// OpenCV can be used to read images.
#include <opencv2/opencv.hpp>
// The VLFeat header files need to be declared external.
extern "C" {
#include "vl/generic.h"
#include "vl/slic.h"
}
int main() {
// Read the Lenna image. The matrix 'mat' will have 3 8 bit channels
// corresponding to BGR color space.
cv::Mat mat = cv::imread("Lenna.png", CV_LOAD_IMAGE_COLOR);
// Convert image to one-dimensional array.
float* image = new float[mat.rows*mat.cols*mat.channels()];
for (int i = 0; i < mat.rows; ++i) {
for (int j = 0; j < mat.cols; ++j) {
// Assuming three channels ...
image[j + mat.cols*i + mat.cols*mat.rows*0] = mat.at<cv::Vec3b>(i, j)[0];
image[j + mat.cols*i + mat.cols*mat.rows*1] = mat.at<cv::Vec3b>(i, j)[1];
image[j + mat.cols*i + mat.cols*mat.rows*2] = mat.at<cv::Vec3b>(i, j)[2];
}
}
// The algorithm will store the final segmentation in a one-dimensional array.
vl_uint32* segmentation = new vl_uint32[mat.rows*mat.cols];
vl_size height = mat.rows;
vl_size width = mat.cols;
vl_size channels = mat.channels();
// The region size defines the number of superpixels obtained.
// Regularization describes a trade-off between the color term and the
// spatial term.
vl_size region = 30;
float regularization = 1000.;
vl_size minRegion = 10;
vl_slic_segment(segmentation, image, width, height, channels, region, regularization, minRegion);
// Convert segmentation.
int** labels = new int*[mat.rows];
for (int i = 0; i < mat.rows; ++i) {
labels[i] = new int[mat.cols];
for (int j = 0; j < mat.cols; ++j) {
labels[i][j] = (int) segmentation[j + mat.cols*i];
}
}
// Compute a contour image: this actually colors every border pixel
// red such that we get relatively thick contours.
int label = 0;
int labelTop = -1;
int labelBottom = -1;
int labelLeft = -1;
int labelRight = -1;
for (int i = 0; i < mat.rows; i++) {
for (int j = 0; j < mat.cols; j++) {
label = labels[i][j];
labelTop = label;
if (i > 0) {
labelTop = labels[i - 1][j];
}
labelBottom = label;
if (i < mat.rows - 1) {
labelBottom = labels[i + 1][j];
}
labelLeft = label;
if (j > 0) {
labelLeft = labels[i][j - 1];
}
labelRight = label;
if (j < mat.cols - 1) {
labelRight = labels[i][j + 1];
}
if (label != labelTop || label != labelBottom || label!= labelLeft || label != labelRight) {
mat.at<cv::Vec3b>(i, j)[0] = 0;
mat.at<cv::Vec3b>(i, j)[1] = 0;
mat.at<cv::Vec3b>(i, j)[2] = 255;
}
}
}
// Save the contour image.
cv::imwrite("Lenna_contours.png", mat);
return 0;
}
In addition, have a look at README.md within the GitHub repository. The following figures show some example outputs of setting the regularization to 1 (100,1000) and setting the region size to 30 (20,40).
Figure 1: Superpixel segmentation with region size set to 30 and regularization set to 1.
Figure 2: Superpixel segmentation with region size set to 30 and regularization set to 100.
Figure 3: Superpixel segmentation with region size set to 30 and regularization set to 1000.
Figure 4: Superpixel segmentation with region size set to 20 and regularization set to 1000.
Figure 5: Superpixel segmentation with region size set to 20 and regularization set to 1000.

Finding Local Maxima Grayscale Image opencv

I am trying to create my personal Blob Detection algorithm
As far as I know I first must create different Gaussian Kernels with different sigmas (which I am doing using Mat kernel= getGaussianKernel(x,y);) Then get the Laplacian of that kernel and then filter the Image with that so I create my scalespace. Now I need to find the Local Maximas in each result Image of the scalespace. But I cannot seem to find a proper way to do so.... my Code so far is
vector <Point> GetLocalMaxima(const cv::Mat Src,int MatchingSize, int Threshold)
{
vector <Point> vMaxLoc(0);
if ((MatchingSize % 2 == 0) ) // MatchingSize has to be "odd" and > 0
{
return vMaxLoc;
}
vMaxLoc.reserve(100); // Reserve place for fast access
Mat ProcessImg = Src.clone();
int W = Src.cols;
int H = Src.rows;
int SearchWidth = W - MatchingSize;
int SearchHeight = H - MatchingSize;
int MatchingSquareCenter = MatchingSize/2;
uchar* pProcess = (uchar *) ProcessImg.data; // The pointer to image Data
int Shift = MatchingSquareCenter * ( W + 1);
int k = 0;
for(int y=0; y < SearchHeight; ++y)
{
int m = k + Shift;
for(int x=0;x < SearchWidth ; ++x)
{
if (pProcess[m++] >= Threshold)
{
Point LocMax;
Mat mROI(ProcessImg, Rect(x,y,MatchingSize,MatchingSize));
minMaxLoc(mROI,NULL,NULL,NULL,&LocMax);
if (LocMax.x == MatchingSquareCenter && LocMax.y == MatchingSquareCenter)
{
vMaxLoc.push_back(Point( x+LocMax.x,y + LocMax.y ));
// imshow("W1",mROI);cvWaitKey(0); //For gebug
}
}
}
k += W;
}
return vMaxLoc;
}
which I found in this thread here, which it supposedly returns a vector of points where the maximas are. it does return a vector of points but all the x and y coordinates of each point are always -17891602... What to do???
Please if you are to lead me in something else other than correcting my code be informative because I know nothing about opencv. I am just learning
The problem here is that your LocMax point is declared inside the inner loop and never initialized, so it's returning garbage data every time. If you look back at the StackOverflow question you linked, you'll see that their similar variable Point maxLoc(0,0) is declared at the top and constructed to point at the middle of the search window. It only needs to be initialized once. Subsequent loop iterations will replace the value with the minMaxLoc function result.
In summary, remove this line in your inner loop:
Point LocMax; // delete this
And add a slightly altered version near the top:
vector <Point> vMaxLoc(0); // This was your original first line
Point LocMax(0,0); // your new second line
That should get you started anyway.
I found it guys. The problem was my threshold was too high. I do not understand why it gave me negative points instead of zero points but lowering the threshold worked