Please have a look at the following code
using namespace cv;
double alpha = 1.6;
int beta = 50;
int i = 0;
IplImage* input_img = cvLoadImage("c:\\Moori.jpg", CV_LOAD_IMAGE_GRAYSCALE);
IplImage* imageGray = cvCreateImage(cvSize(input_img->width, input_img->height), IPL_DEPTH_8U, 1);
for( int y = 0; y < input_img->height; y++ )
{
for( int x = 0; x < input_img->width; x++ )
{
i = y * imageGray->width + x;
imageGray->imageData[i] = (alpha * input_img->imageData[i]) + beta;
}
}
cvNamedWindow("Image IplImage", 1);
cvShowImage("Image IplImage", imageGray);
waitKey();
cvReleaseImage(&imageGray);
cvReleaseImage(&input_img);
cvDestroyWindow("Image IplImage");
when I run this code, it shows an image with many dark pixels.
But, when i run the code, which is available at:
http://docs.opencv.org/doc/tutorials/core/basic_linear_transform/basic_linear_transform.html
it works fine. I want to do by IplImage. Please help
saturate_cast is for c++.
http://docs.opencv.org/modules/core/doc/intro.html
Finally, I have solved this problem.
IplImage* img;
cvNamedWindow("Display");
while(true)
{
img = cvLoadImage("Moori.jpg");
CvScalar brVal = cvScalarAll(abs(10.0));
cvAddS(img, brVal, img, NULL);
IplImage *pTempImg = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, img->nChannels);
cvSet( pTempImg, cvScalarAll(1), NULL );
double scale = 1.5;
cvMul(img, pTempImg, img, scale);
cvReleaseImage(&pTempImg);
cvShowImage("Display", img);
cvReleaseImage(&img);
int c=cvWaitKey(10);
if(c==27) break;
}
cvDestroyWindow("Display");
You dont have to cast the image values to uchar. You have to reinterpret the values as uchar. It Means you have to assume that the data bits actually represent an unsigned char, regardless of the type of pointer. It can be done as follows:
uchar* ptr = reinterpret_cast<uchar*>(imageGray->imageData);
ptr[i] = saturate_cast<uchar>(alpha * ptr[i] + beta);
If you are using C++ I am not sure why anybody would want to use IplImage. But your problem is this line
imageGray->imageData[i] = (alpha * input_img->imageData[i]) + beta;
It can overflow. Also imageData is a char*, and a char may be signed or unsigned, you need to make it unsigned. You need use saturate_cast to prevent overflow, and a cast to get rid of the signed char:
imageGray->imageData[i] = saturate_cast<uchar>((alpha * static_cast<uchar>(input_img->imageData[i])) + beta);
You can use this little program to see what is going on:
#include <opencv2/core/core.hpp>
#include <iostream> // std::cout
#include <vector> // std::vector
int main(int argc, char** argv)
{
double alpha = 1.6;
int beta = 50;
std::vector<uchar> z;
for(int i = 0; i <= 255; ++i)
z.push_back(i);
char* zp = reinterpret_cast<char *>(&z[0]);
for(int i = 0; i <= 255; ++i)
std::cout << i << " -> " << int(cv::saturate_cast<uchar>(alpha * static_cast<uchar>(zp[i]) + beta)) << std::endl;
}
Related
When running this code with the same image and mask I occasionally get values that differ previously. For example
Normal/Expected Results
Abnormal Results
As can be seen in the two results I somehow receive negative RGB values. The Abnormal Results show up around every 5-8 runs for the exact same image with the exact same mask.
What do I need to change to prevent the occasional abnormal result?
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string>
using namespace cv;
using namespace std;
float get_color(Mat img,Mat &mask){
Mat img1 = img;
Mat hist;
int dims = 1;
int histSize = 255;
float hranges[] = { 0, 255 };
const float *ranges = {hranges};
calcHist(&img1,1,0,mask,hist, dims, &histSize, &ranges ,true ,false);
int sum=0;
for(int i = 0;i<256;i++){
sum += hist.at<float>(i,0);
}
Mat weights = hist/sum;
float hist_avg=0.0;
for(int i = 0;i<256;i++){
hist_avg += i*weights.at<float>(i,0);
}
return hist_avg;
}
int main(int argc, char** argv){
Mat aa = imread("/Users/dnguyen/Desktop/snapshot207042/pic.jpg", CV_LOAD_IMAGE_COLOR);
vector<Mat> bgr;
split(aa, bgr);
Mat b = bgr[0];
Mat g = bgr[1];
Mat r = bgr[2];
for(unsigned int i=1;i<23;i++){
stringstream ss;
ss << i;
string str = ss.str();
string file_name = "/Users/dnguyen/Desktop/okay/data/card_masks/"+str+"_mask.png";
Mat mask = imread(file_name,0);
Mat cc;
threshold(mask,cc,90,255,THRESH_BINARY);
float b_avg = get_color(b, cc);
float g_avg = get_color(g, cc);
float r_avg = get_color(r, cc);
cout << b_avg << ","<< g_avg << "," << r_avg << endl;
}
}
This some parts of my opencv image processing codes.In it, I generate two dynamic arrays to store the total numbers of black points per col/row in binary image.
Here are the codes:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat srcImg = imread("oura.bmp");
width = srcImg.cols - 2;
height = srcImg.rows - 2;
Mat srcGrey;
Mat srcRoi(srcImg, Rect(1, 1, width, height));
cvtColor(srcRoi, srcGrey, COLOR_BGR2GRAY);
int thresh = 42;
int maxval = 255;
threshold(srcGrey, srcRoiBina, thresh, maxval, THRESH_BINARY);
int *count_cols = new int[width] ();
int *count_rows = new int[height] ();
for (int i = 0; i < width; i++)
{
cout << count_cols[i] << endl;
}
for (int i = 0; i < height; i++)
{
uchar *data = srcRoiBina.ptr<uchar>(i);
for (int j = 0; j < width; j++)
{
if (data[j] == 0)
{
count_cols[j]++;
count_rows[i]++;
}
}
}
delete[] count_cols;
delete[] count_rows;
return 0;
}
My question is that: if I use the follow codes
int *count_cols = new int[width];
int *count_rows = new int[height];
memset(count_cols, 0, sizeof(count_cols));
memset(count_rows, 0, sizeof(count_rows));
for (int i = 0; i < width; i++)
{
cout << count_cols[i] << endl;
}
to replace the corresponding codes below, why the dynamic arrays can not be initialized to zero? It seems that the memset does not work.
Platform: Visual Stdio 2013 + opencv 3.0.0
Could you please help me?
Additionally, the original image oura.bmp is 2592*1944.Thus the length of the dynamic array count_cols is 2590(ie, 2592-2). Is there some potential problems?
count_cols is of type int*, so sizeof(count_cols) will be 8 (64bit) or 4 (32bit). You'll want to use sizeof(int) * width instead (and similarly for rows).
sizeof(count_rows) is returning the size of the pointer, not the size of the array.
Use height * sizeof(int) instead. Same applies for the columns too.
I have some problems when using Stitcher class.
First, I use ORB Feature Finder because it's faster than SURF.
but it's still slow.
Second, Stitcher class accuracy is too low.
Third, How can I get more performance by using Stitcher class?
Additional, How can I catch directions between two images?
This is my code.
Thank you.
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/stitching.hpp"
#include "opencv2/features2d.hpp"
using namespace cv;
using namespace std;
void overlayImage(const cv::Mat &background, const cv::Mat &foreground, cv::Mat &output, cv::Point2i location);
int main(int argc, char* argv[])
{
Mat first;
Mat second;
Mat m_first;
Mat m_second;
vector<Mat> images;
// vector<Mat> re_images;
Mat panorama;
Mat result;
unsigned long t;
t = getTickCount();
first = imread(argv[1], CV_LOAD_IMAGE_COLOR);
second = imread(argv[2], CV_LOAD_IMAGE_COLOR);
//Mat m_first = Mat::zeros( first.size(), first.type() );
//Mat m_second = Mat::zeros( second.size(), second.type() );
/*
for( int y = 0; y < first.rows; y++ ) {
for( int x = 0; x < first.cols; x++ ) {
for( int c = 0; c < 3; c++ ) {
m_first.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( 1.2*( first.at<Vec3b>(y,x)[c] ) + 20 );
}
}
}
for( int y = 0; y < second.rows; y++ ){
for( int x = 0; x < second.cols; x++ ) {
for( int c = 0; c < 3; c++ ) {
m_second.at<Vec3b>(y,x)[c] =
saturate_cast<uchar>( 1.2*( second.at<Vec3b>(y,x)[c] ) + 20 );
}
}
}
*/
//imwrite("first.png", m_first);
//imwrite("second.png", m_second);
resize(first, m_first, Size(640, 480));
resize(second, m_second, Size(640, 480));
images.push_back(m_first);
images.push_back(m_second);
Stitcher stitcher = Stitcher::createDefault(false);
//Stitcher::Status status = stitcher.stitch(imgs, pano);
//stitcher.setWarper(new PlaneWarper());
stitcher.setWarper(new SphericalWarper());
// stitcher.setWarper(new CylindricalWarper());
stitcher.setFeaturesFinder(new detail::OrbFeaturesFinder(Size(3,1),1500));
// stitcher.setRegistrationResol(0.6);
// stitcher.setSeamEstimationResol(0.1);
// stitcher.setCompositingResol(0.5);
//stitcher.setPanoConfidenceThresh(1);
stitcher.setWaveCorrection(true);
stitcher.setWaveCorrectKind(detail::WAVE_CORRECT_HORIZ);
stitcher.setFeaturesMatcher(new detail::BestOf2NearestMatcher(false,0.3));
stitcher.setBundleAdjuster(new detail::BundleAdjusterRay());
stitcher.setBlender(new detail::MultiBandBlender());
stitcher.stitch(images, panorama);
printf("%.2lf sec \n", (getTickCount() - t) / getTickFrequency() );
Rect rect(panorama.cols / 2 - 320, panorama.rows / 2 - 240, 640, 480);
Mat subimage = panorama(rect);
Mat car = imread("car.png");
overlayImage(subimage, car, result, cv::Point(320 - (car.cols / 2), 240 - (car.rows / 2 )));
imshow("panorama", result);
// resize(panorama, result, Size(640, 480));
imwrite("result.jpg", result);
waitKey(0);
return 0;
}
void overlayImage(const cv::Mat &background, const cv::Mat &foreground, cv::Mat &output, cv::Point2i location)
{
background.copyTo(output);
// start at the row indicated by location, or at row 0 if location.y is negative.
for(int y = std::max(location.y , 0); y < background.rows; ++y)
{
int fY = y - location.y; // because of the translation
// we are done of we have processed all rows of the foreground image.
if(fY >= foreground.rows)
break;
// start at the column indicated by location,
// or at column 0 if location.x is negative.
for(int x = std::max(location.x, 0); x < background.cols; ++x)
{
int fX = x - location.x; // because of the translation.
// we are done with this row if the column is outside of the foreground image.
if(fX >= foreground.cols)
break;
// determine the opacity of the foregrond pixel, using its fourth (alpha) channel.
double opacity =
((double)foreground.data[fY * foreground.step + fX * foreground.channels() + 3])
/ 255.;
// and now combine the background and foreground pixel, using the opacity,
// but only if opacity > 0.
for(int c = 0; opacity > 0 && c < output.channels(); ++c)
{
unsigned char foregroundPx =
foreground.data[fY * foreground.step + fX * foreground.channels() + c];
unsigned char backgroundPx =
background.data[y * background.step + x * background.channels() + c];
output.data[y*output.step + output.channels()*x + c] =
backgroundPx * (1.-opacity) + foregroundPx * opacity;
}
}
}
}
FAST feature detector is faster than SURF and ORB.
Moreover, finding 1500 features in a 640*480 picture takes too much time. 300 features is ok. So you can use this code instead:
detail::OrbFeaturesFinder(Size(3,1),300));
Stitcher Class is so slow. I suggest you try to implement stitcher class yourself. Try using feature detectors, descriptors, then matching and after that find homography then making mask and then warping.
I don't understand your third question, "How can I catch directions between two images?". What do you mean exactly?
I'm having problems with the DFT function in OpenCV 2.4.8 for c++.
I used an image of a 10 phases sinus curve to compare the old cvDFT() with the newer c++ function DFT() (one dimensional DFT row-wise).
The old version gives me logical results: very high peak at pixel 0 and 10, the rest being almost 0.
The new version gives me strange results with peaks all over the spectrum.
Here is my code:
#include "stdafx.h"
#include <opencv2\core\core_c.h>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc_c.h>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\highgui\highgui_c.h>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\legacy\compat.hpp>
using namespace cv;
void OldMakeDFT(Mat original, double* result)
{
const int width = original.cols;
const int height = 1;
IplImage* fftBlock = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
IplImage* imgReal = cvCreateImage(cvSize(width, height), IPL_DEPTH_32F, 1);
IplImage* imgImag = cvCreateImage(cvSize(width, height), IPL_DEPTH_32F, 1);
IplImage* imgDFT = cvCreateImage(cvSize(width, height), IPL_DEPTH_32F, 2);
Rect roi(0, 0, width, 1);
Mat image_roi = original(roi);
fftBlock->imageData = (char*)image_roi.data;
//cvSaveImage("C:/fftBlock1.png", fftBlock);
cvConvert(fftBlock, imgReal);
cvMerge(imgReal, imgImag, NULL, NULL, imgDFT);
cvDFT(imgDFT, imgDFT, (CV_DXT_FORWARD | CV_DXT_ROWS));
cvSplit(imgDFT, imgReal, imgImag, NULL, NULL);
double re,imag;
for (int i = 0; i < width; i++)
{
re = ((float*)imgReal->imageData)[i];
imag = ((float*)imgImag->imageData)[i];
result[i] = re * re + imag * imag;
}
cvReleaseImage(&imgReal);
cvReleaseImage(&imgImag);
cvReleaseImage(&imgDFT);
cvReleaseImage(&fftBlock);
}
void MakeDFT(Mat original, double* result)
{
const int width = original.cols;
const int height = 1;
Mat fftBlock(1,width, CV_8UC1);
Rect roi(0, 0, width, height);
Mat image_roi = original(roi);
image_roi.copyTo(fftBlock);
//imwrite("C:/fftBlock2.png", fftBlock);
Mat planes[] = {Mat_<float>(fftBlock), Mat::zeros(fftBlock.size(), CV_32F)};
Mat complexI;
merge(planes, 2, complexI);
dft(complexI, complexI, DFT_ROWS); //also tried with DFT_COMPLEX_OUTPUT | DFT_ROWS
split(complexI, planes);
double re, imag;
for (int i = 0; i < width; i++)
{
re = (float)planes[0].data[i];
imag = (float)planes[1].data[i];
result[i] = re * re + imag * imag;
}
}
bool SinusFFTTest()
{
const int size = 1024;
Mat sinTest(size,size,CV_8UC1, Scalar(0));
const int n_sin_curves = 10;
double deg_step = (double)n_sin_curves*360/size;
for (int j = 0; j < size; j++)
{
for (int i = 0; i <size; i++)
{
sinTest.data[j*size+i] = 127.5 * sin(i*deg_step*CV_PI/180) + 127.5;
}
}
double* result1 = new double[size];
double* result2 = new double[size];
OldMakeDFT(sinTest,result1);
MakeDFT(sinTest,result2);
bool identical = true;
for (int i = 0; i < size; i++)
{
if (abs(result1[i] - result2[i]) > 1000)
{
identical = false;
break;
}
}
delete[] result1;
delete[] result2;
return identical;
}
int _tmain(int argc, _TCHAR* argv[])
{
if (SinusFFTTest())
{
printf("identical");
}
else
{
printf("different");
}
getchar();
return 0;
}
Could someone explain the difference?
imgReal - is not filled with zeroes by default.
The bug in in the MakeDFT() function:
re = (float)planes[0].data[i];
imag = (float)planes[1].data[i];
data[i]'s type is uchar, and its conversion to float is not right.
The fix:
re = planes[0].at<float>(0,i);
imag = planes[1].at<float>(0,i);
After this change, the old and the new DFT versions gives the same results. Or, you can use cv::magnitude() instead of calculating the sum of squares of re and imag:
Mat magn;
magnitude(planes[0], planes[1], magn);
for (int i = 0; i < width; i++)
result[i] = pow(magn.at<float>(0,i),2);
This gives also the same result as the old cvDFT.
I can't seem to get this to work. I'm trying to get the pixel value of an image but first need to change the color of the image, but since I cannot use int or just Mat because the values are not whole numbers, I have to use <float> and because of that errors pop up when I try to run this on the cmd.
int main(int argc, char **argv)
{
Mat img = imread(argv[1]);
ofstream myfile;
Mat_<float> MatBlue = img;
int rows1 = MatBlue.rows;
int cols1 = MatBlue.cols;
for(int x = 0; x < cols1; x++) {
for(int y = 0; y < rows1; y++) {
float val = MatBlue.at<cv::Vec3b>(y, x)[1];
MatBlue.at<cv::Vec3b>(y, x)[0] = val + 1;
}
}
}
To achieve your goal, i.e. type conversion, use cv::Mat::convertTo.
Example: img.convertTo(MatBlue, CV_32F) or img.convertTo(MatBlue, CV_32F, 1.0/255.0) (to have values normalized between 0 and 1).
You are mixing char and float pointer types in your code.