Can anyone recommend a lightweight mean shift clustering implementation in C++? I am already using OpenCV, however their mean shift implementation is for tracking, not clustering. I have seen EDISON, however, this is for image segmentation and not clustering.
I could implement it myself, however would rather not invest the time, and not take the risk of bugs.
Thanks
This is old, but I am working with mean shift right now so I thought it best to answer.
I think I understand the distinction you are making here, but when you say you are looking for mode detection this is vague in the technical sense as from the point of view of the algorithm as the algorithm inherently is for searching for "modes", which are the local minima or maxima depending on how you frame the optimization problem (Gradient descent or ascent).
This source, which was found on the EDISON site, claims to be a c++ implementation of the mean shift clustering algorithm, but as discussed above, clustering is the main implementation of the mode seeking behavior that all other uses of mean shift is based on, especially segmentation, so you can certainly use the EDISON source to find a clustering implementation, even if you have to search through it a bit.
I also found this Github project, for what it is worth, but I haven't worked with it before.
LAST NOTE: I also noticed you said "lightweight" implementation. Note that mean shift is not a very efficient algorithm (i think it is something like O(N^3), but I will check that). That said, it can still be efficiently implemented, though how that should be gauged is more ambiguous. Needless to say, Quick Shift, an attempt by UCLA researchers to solve the issues of the more efficient medoid shift, a similar non-parametric mode seeking algorithm, might be more like what you are looking for in a "lightweight" algorithm.
Here is my C++ version of mean shift object tracking method. To run the code successfully, you need to add the tf.h header file to the main code directory.
#include "tf.h" // include the header file
using namespace cv;
using namespace std;
#include <stdio.h>
makerect mkr; // rectangle for encompassing target
// rcs for row coordination of target window center
//ccs for column coordination of target window center
double rcs=0,ccs=0;
// w for width of target window
// l for length of target window
double W=70,L=60;
const int mySizes[3]={16,16,16}; // vector for number of histogram bins
cv::Mat q4hsv = Mat::zeros(3,mySizes,CV_64F); // initializing histogram variable
uchar nbins=16; // var for num of histogram bins
int main(void){
printf("enter 14 or 36: \t"); // enter number of input video name
uint flag; // var for video flag or number
cin>>flag;
Mat ref4frame; // reference frame which is used for initializing mean shift parameters
char filename [50];
sprintf(filename,"im%d.avi",flag);
VideoCapture capture(filename);
if( !capture.isOpened() )
throw "Error when reading steam_avi";
unsigned long int f4counter=0; // frame counter var
histhsv hsv; // instantiating histhsv class
for (f4counter=1;f4counter<=40000000;f4counter++){ // a big number to support many frames
capture >> ref4frame; //reading input image from specified directory
if( !(ref4frame.data )) // checking the read status
{
printf("Cannot load file image %s\n", filename);
break; }
uchar ndiv = uchar(256/nbins); // division value to which intesity values are divided
if (f4counter==1) { // special for 1st frame
char modelname[20];
if(flag==36){
sprintf(modelname,"data%d.png",flag);
}
else if (flag==14){
sprintf(modelname,"data%d.jpg",flag);
}
// imread is defined in tf.h
Mat img = imread(modelname,1);//reads 1st image
if( !(img.data ))//check if file loading is ok
{
printf("Cannot load file image %s\n", modelname);
break; }
hsv.img=img;//assign new image to hsv object (calculates hsv or rgb hist)
hsv.run();//run the histogram calculator
// assign temporary hsv object to reference hist q4hsv object
for (int i=0;i<16;i++){
for(int j=0;j<16;j++){
for(int k=0;k<16;k++){
q4hsv.at<double>(i,j,k)=hsv.q[i][j][k];
}
}
}
}
if(f4counter<5){averageglobalhsv(ref4frame,q4hsv,rcs,ccs);}
averagelocalhsv(ref4frame,q4hsv,rcs,ccs);//normalizing histogram values (0-1)
Point pt1; pt1.x=ccs; pt1.y=rcs;
int thickness=4;//thickness of marker - here is a circle
int lineType=8;
int shift=0;
RNG rng(0xFFFFFFFF);
cv::circle(ref4frame, pt1, 5, randomColor(rng), thickness, lineType,
shift); //marking object center with a circle
myimshow("reference frame",ref4frame);//show current image
waitKey(1);
}
int c=waitKey(0);
//release memory
ref4frame.release();
destroyAllWindows();
return 0;
}
here is the tf.h header file contents:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2\opencv.hpp"
#include "core\core.hpp"
#include <cstdio>
#include <iostream>
#include <fstream>
#include <math.h>
using namespace cv;
using namespace std;
// makerect class: to create the desired size encompassing window
class makerect
{
public:
double rcs,ccs,w,l; // ctl row, ctl column, width, length
uint rmin,rmax,cmin,cmax,height,length;//min max coordination vars
void run(void);
makerect();
};
makerect::makerect(){
rmin=0;rmax=0;cmin=0;cmax=0;rcs=0;ccs=0;w=0;l=0;
}
void makerect::run(){
//not that all points must be either integer or floating point
rmin=uint(rcs-floor(w/2));//min row coordination
rmax=uint(rmin+w);//max row coordination
cmin=uint (ccs-floor(l/2));//min column coordination
cmax=uint(cmin+l);//max column coordination
if(cmax>length){cmax=length;cmin=cmax-l;// checking column to be inside image}
if(rmax>height){rmax=height;rmin=rmax-w;//checking row to be inside image}
}
static Scalar randomColor(RNG& rng)
{
int icolor = (unsigned)rng;
return Scalar(icolor&255, (icolor>>8)&255, (icolor>>16)&255);
}
//myimshow: is a function to to show image
void myimshow(char* name4window,Mat &tmp4image){
namedWindow(name4window,1); imshow(name4window,tmp4image);
}
void averageglobalhsv(Mat ref4frame,Mat &f,double &rcs,double &ccs)
{
Mat img;
cvtColor(ref4frame,img,CV_BGR2HSV);//rgb2hsv conversion
uint n4rowsref=ref4frame.rows;// num of rows
uint n4colsref=ref4frame.cols;// num of cols
double *im4bp = new double [n4rowsref*n4colsref];//1-D dynamic array equal to image pixels
uint nbins=16;// num of histogram bins
uint ndiv=256/nbins; //division value to which intensities are divided
//vars for image moments (zero to second moments)
double m00=0,m01=0,m10=0,m20=0,m02=0,m11=0,w=0;
uint R=0,G=0,B=0; //red bin num, green bin num, blue bin num
for(uint i=0;i<n4rowsref;i++){ //loop through all image rows
for(uint j=0;j<n4colsref;j++){//loop through all image columns
Vec3b inten=img.at<Vec3b>(i,j);//a vector of three element
R=inten.val[2]; G=inten.val[1]; B=inten.val[0];
R/=ndiv; G/=ndiv; B/=ndiv;//calculating the bin to which current pixel intensity belong
im4bp[i*n4colsref+j]=1.3*sqrt(f.at<double>(R,G,B));//calculating spatial weighted kernel histogram formula
}
}
for(uint i=0;i<n4rowsref;i++){//loop through all image rows
for(uint j=0;j<n4colsref;j++){//loop through all image columns
w=im4bp[j+n4colsref*i];// weight for pixel at (i,j)
m01=m01+double(i)*w;//first moment on y/row coordination
m10=m10+double(j)*w;//first moment on x/column coordination
m00=m00+w;//zeroth moment which is sum of all moments
}
}
if(m00>0){
rcs=ceil(m01/m00);//central point for row
ccs=ceil(m10/m00);}//central point for column
delete im4bp;//cleaning memory
}
void averagelocalhsv(Mat ref4frame,Mat &f,double &rcs,double &ccs)
{
Mat img;
cvtColor(ref4frame,img,CV_BGR2HSV);
makerect mkr;
int sz[]={2,2};
uint n4rowsref=ref4frame.rows;
uint n4colsref=ref4frame.cols;
double *im4bp = new double [n4rowsref*n4colsref];
uint nbins=16;
uint ndiv=256/nbins;
double m00=0,m01=0,m10=0,m20=0,m02=0,m11=0,w=0,Dxx,Dyy,Dxy;
uint R=0,G=0,B=0;
for(uint i=0;i<n4rowsref;i++){
for(uint j=0;j<n4colsref;j++){
Vec3b inten=img.at<Vec3b>(i,j);
R=inten.val[2]; G=inten.val[1]; B=inten.val[0];
R/=ndiv; G/=ndiv; B/=ndiv;
im4bp[i*n4colsref+j]=1.3*sqrt(f.at<double>(R,G,B));
}
}
for(int iter=1;iter<5;iter++){
mkr.rcs=rcs;mkr.ccs=ccs;mkr.w=100;mkr.l=100;mkr.height=ref4frame.rows;
mkr.length=ref4frame.cols; mkr.run();
m00=0;m01=0;m10=0;m20=0;m02=0;m11=0;
for(uint i=mkr.rmin;i<mkr.rmax;i=i+1){
for(uint j=mkr.cmin;j<mkr.cmax;j=j+1){
w=im4bp[j+n4colsref*i];
m01=m01+double(i)*w;
m10=m10+double(j)*w;
m00=m00+w;
}
}
}
if(m00>0){
rcs=ceil(m01/m00);
ccs=ceil(m10/m00);
}
delete im4bp;
}
class histhsv{
public:
histhsv();
void run(void);
Mat img;
double q[16][16][16];
};
histhsv::histhsv(){};
void histhsv::run(void){
//Mat hsv4image;
double sum4hist=0;
uchar nbins=16;
uchar ndiv=256/nbins;
double wmax =0;;
double r_center=0;
double c_center =0;
r_center = img.rows/2;
c_center = img.cols/2;
for (int i=0;i<nbins;i++){for(int j=0;j<nbins;j++){for(int k=0;k<nbins;k++){
q[i][j][k]=0; } } };
cvtColor(img,img,CV_BGR2HSV);
int H=0,S=0,V=0;
for(int r=0;r<img.rows;r++){
for(int c=0;c<img.cols;c++){
Vec3b intensity = img.at<Vec3b>(r,c);
H=intensity.val[0]/ndiv;
S=intensity.val[1]/ndiv;
V=intensity.val[2]/ndiv;
q[H][S][V]+=wmax-(pow(r-r_center,2)+pow(c-c_center,2));
sum4hist+=q[H][S][V];
}
}
for (int i=0;i<nbins;i++){
for(int j=0;j<nbins;j++){
for(int k=0;k<nbins;k++){
q[i][j][k]/=sum4hist;
}
}
}
}
Related
So i found this link regarding my question, but it is for c#
Create a PNG from an array of bytes
I have a variable int array of numbers.
i will call it "pix[ ]"
for now it can be any size from 3 to 256, later possibly bigger.
What i want to do now, is to convert it into a pixel image.
I am still a noobin c++ so pleas excuse me.
I tried to download some libaries that make working with libpng easier, but they do not seem to be working (ubuntu, code::blocks)
So i have questions in the following:
1) how do you create a new bitmap (which libaries, which command)?
2) how do i fill it with information from "pix[ ]" ?
3) how do i save it?
if it is a repost of a question i am happy about a link also ;)
Here is what i worked out so far, thanks for your help.
int main(){
FILE *imageFile;
int x,y,pixel,height=2,width=3;
imageFile=fopen("image.pgm","wb");
if(imageFile==NULL){
perror("ERROR: Cannot open output file");
exit(EXIT_FAILURE);
}
fprintf(imageFile,"P3\n"); // P3 filetype
fprintf(imageFile,"%d %d\n",width,height); // dimensions
fprintf(imageFile,"255\n"); // Max pixel
int pix[100] {200,200,200, 100,100,100, 0,0,0, 255,0,0, 0,255,0, 0,0,255};
fwrite(pix,1,18,imageFile);
fclose(imageFile);
}
i have not fully understood what it does. i can open the output image, but it is not a correct representation of the Array.
If i change things around, for example making a 2 dimensional array, then the image viewer tells me "expected an integer" and doesn't show me an image.
So far so good.
As i have the array before the image i created a function aufrunden to round up to the next int number because i want to create a square image.
int aufrunden (double h)
{
int i =h;
if (h-i == 0)
{
return i;
}
else
{
i = h+1;
return i;
}
}
This function is used in the creation of the image.
If the image is bigger than the information the array provides like this (a is the length of th array)
double h;
h= sqrt(a/3.0);
int i = aufrunden(h);
FILE *imageFile;
int height=i,width=i;
It might happen now, that the array is a=24 long. aufrunden makes the image 3x3 so it has 27 values...meaning it is missing the values for 1 pixel.
Or worse it is only a=23 long. also creating a 3x3 image.
What will fwrite(pix,1,18,imageFile); write in those pixels for information? It would be best if the remaing values are just 0.
*edit never mind, i will just add 0 to the end of the array until it is filling up the whole square...sorry
Consider using a Netpbm format (pbm, pgm, or ppm).
These images are extremely simple text files that you can write without any special libraries. Then use some third-party software such as ImageMagick, GraphicsMagick, or pnmtopng to convert your image to PNG format. Here is a wiki article describing the Netpbm format.
Here's a simple PPM image:
P3 2 3 255
0 0 0 255 255 255
255 0 0 0 255 255
100 100 100 200 200 200
The first line contains "P3" (the "magic number identifying it as a text-PPM), 2 (width), 3 (height), 255 (maximum intensity).
The second line contains the two RGB pixels for the top row.
The third and fourth lines each contain the two RGB pixels for rows 2 and 3.
Use a larger number for maximum intensity (e.g. 1024) if you need a larger range of intensities, up to 65535.
Edited by Mark Setchell beyond this point - so I am the guilty party!
The image looks like this (when the six pixels are enlarged):
The ImageMagick command to convert, and enlarge, is like this:
convert image.ppm -scale 400x result.png
If ImageMagick is a bit heavyweight, or difficult to install you can more simply use the NetPBM tools (from here) like this (it's a single precompiled binary)
pnmtopng image.ppm > result.png
If, as it seems, you have got Magick++ and are happy to use that, you can write your code in C/C++ like this:
////////////////////////////////////////////////////////////////////////////////
// sample.cpp
// Mark Setchell
//
// ImageMagick Magick++ sample code
//
// Compile with:
// g++ sample.cpp -o sample $(Magick++-config --cppflags --cxxflags --ldflags --libs)
////////////////////////////////////////////////////////////////////////////////
#include <Magick++.h>
#include <iostream>
using namespace std;
using namespace Magick;
int main(int argc,char **argv)
{
unsigned char pix[]={200,200,200, 100,100,100, 0,0,0, 255,0,0, 0,255,0, 0,0,255};
// Initialise ImageMagick library
InitializeMagick(*argv);
// Create Image object and read in from pixel data above
Image image;
image.read(2,3,"RGB",CharPixel,pix);
// Write the image to a file - change extension if you want a GIF or JPEG
image.write("result.png");
}
You are not far off - well done for trying! As far as I can see, you only had a couple of mistakes:
You had P3 where you would actually need P6 if writing in binary.
You were using int type for your data, whereas you need to be using unsigned char for 8-bit data.
You had the width and height interchanged.
You were using the PGM extension which is for Portable Grey Maps, whereas your data is colour, so you need to use the PPM extension which is for Portable Pix Map.
So, the working code looks like this:
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *imageFile;
int x,y,pixel,height=3,width=2;
imageFile=fopen("image.ppm","wb");
if(imageFile==NULL){
perror("ERROR: Cannot open output file");
exit(EXIT_FAILURE);
}
fprintf(imageFile,"P6\n"); // P6 filetype
fprintf(imageFile,"%d %d\n",width,height); // dimensions
fprintf(imageFile,"255\n"); // Max pixel
unsigned char pix[]={200,200,200, 100,100,100, 0,0,0, 255,0,0, 0,255,0, 0,0,255};
fwrite(pix,1,18,imageFile);
fclose(imageFile);
}
If you then run that, you can convert the resulting image to a nice big PNG with
convert image.ppm -scale 400x result.png
If you subsequently need 16-bit data, you would change the 255 to 65535, and store in an unsigned short array rather than unsigned char and when you come to the fwrite(), you would need to write double the number of bytes.
The code below will take an integer array of pixel colors as input and write it to a .bmp bitmap file or, in reverse, read a .bmp bitmap file and store its image contents as an int array. It only requires the <fstream> library. The input parameter path can be for example C:/path/to/your/image.bmp and data is formatted as data[x+y*width]=(red<<16)|(green<<8)|blue;, whereby red, green and blue are integers in the range 0-255 and the pixel position is (x,y).
#include <string>
#include <fstream>
using namespace std;
typedef unsigned int uint;
int* read_bmp(const string path, uint& width, uint& height) {
ifstream file(path, ios::in|ios::binary);
if(file.fail()) println("\rError: File \""+filename+"\" does not exist!");
uint w=0, h=0;
char header[54];
file.read(header, 54);
for(uint i=0; i<4; i++) {
w |= (header[18+i]&255)<<(8*i);
h |= (header[22+i]&255)<<(8*i);
}
const int pad=(4-(3*w)%4)%4, imgsize=(3*w+pad)*h;
char* img = new char[imgsize];
file.read(img, imgsize);
file.close();
int* data = new int[w*h];
for(uint y=0; y<h; y++) {
for(uint x=0; x<w; x++) {
const int i = 3*x+y*(3*w+pad);
data[x+(h-1-y)*w] = (img[i]&255)|(img[i+1]&255)<<8|(img[i+2]&255)<<16;
}
}
delete[] img;
width = w;
height = h;
return data;
}
void write_bmp(const string path, const uint width, const uint height, const int* const data) {
const int pad=(4-(3*width)%4)%4, filesize=54+(3*width+pad)*height; // horizontal line must be a multiple of 4 bytes long, header is 54 bytes
char header[54] = { 'B','M', 0,0,0,0, 0,0,0,0, 54,0,0,0, 40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,24,0 };
for(uint i=0; i<4; i++) {
header[ 2+i] = (char)((filesize>>(8*i))&255);
header[18+i] = (char)((width >>(8*i))&255);
header[22+i] = (char)((height >>(8*i))&255);
}
char* img = new char[filesize];
for(uint i=0; i<54; i++) img[i] = header[i];
for(uint y=0; y<height; y++) {
for(uint x=0; x<width; x++) {
const int color = data[x+(height-1-y)*width];
const int i = 54+3*x+y*(3*width+pad);
img[i ] = (char)( color &255);
img[i+1] = (char)((color>> 8)&255);
img[i+2] = (char)((color>>16)&255);
}
for(uint p=0; p<pad; p++) img[54+(3*width+p)+y*(3*width+pad)] = 0;
}
ofstream file(path, ios::out|ios::binary);
file.write(img, filesize);
file.close();
delete[] img;
}
The code snippet was inspired by https://stackoverflow.com/a/47785639/9178992
For .png images, use lodepng.cpp and lodepng.h:
#include <string>
#include <vector>
#include <fstream>
#include "lodepng.h"
using namespace std;
typedef unsigned int uint;
int* read_png(const string path, uint& width, uint& height) {
vector<uchar> img;
lodepng::decode(img, width, height, path, LCT_RGB);
int* data = new int[width*height];
for(uint i=0; i<width*height; i++) {
data[i] = img[3*i]<<16|img[3*i+1]<<8|img[3*i+2];
}
return data;
}
void write_png(const string path, const uint width, const uint height, const int* const data) {
uchar* img = new uchar[3*width*height];
for(uint i=0; i<width*height; i++) {
const int color = data[i];
img[3*i ] = (color>>16)&255;
img[3*i+1] = (color>> 8)&255;
img[3*i+2] = color &255;
}
lodepng::encode(path, img, width, height, LCT_RGB);
delete[] img;
}
Running the below code with both the Xtion Pro and the DS325 depth cameras gives very different results. The Xtion Pro shows both coloured point cloud and RGB perfectly, whereas the DS325 has many black fuzzy areas in the image, making it unusable for the OpenCV functionality I was intending (after conversion to Mat form).
This link seems to be when XYZ data is captured as NaN. For example, the Xtion Pro shows full RGB fine even when pointed out the window (which makes the majority of XYZ data NaN), whereas doing the same for the DS325 makes almost the whole RGB image show black.
Can someone tell me if this is just an imperfection in the new grabber code? Or is more inherently linked to the differences in mapping for the different hardware?
Running the depthsense viewer application (from primesense SDK) does confirm to me that both depth and full RGB data can be streamed simultaneously, so slightly confused as to why the RGB seems to be being discarded. Any help would be greatly appreciated! Thanks.
Windows, VS2013, PCL 1.8
#include <iostream>
#include <mutex>
#include <boost/thread/mutex.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/format.hpp>
#include <pcl/io/pcd_io.h>
#include <pcl/common/time.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/io/io_exception.h>
#include <pcl/io/openni_grabber.h>
#include <pcl/io/depth_sense_grabber.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/visualization/image_viewer.h>
using namespace pcl::console;
typedef pcl::PointCloud<pcl::PointXYZRGBA> PointCloudT;
std::mutex cloud_mutex;
void cloud_cb_(const PointCloudT::ConstPtr& callback_cloud, PointCloudT::Ptr& new_cloud_,
bool* new_cloud_available_flag)
{
cloud_mutex.lock();
*new_cloud_ = *callback_cloud;
cloud_mutex.unlock();
*new_cloud_available_flag = true;
}
void PointXYZRGBAtoCharArray(pcl::PointCloud<pcl::PointXYZRGBA>::Ptr point_cloud_ptr, unsigned char * Image)
{
for (int i = 0; i < point_cloud_ptr->height; i++)
{
for (int j = 0; j < point_cloud_ptr->width; j++)
{
Image[(i * point_cloud_ptr->width + j) * 3] = point_cloud_ptr->points.at(i * point_cloud_ptr->width + j).r;
Image[(i * point_cloud_ptr->width + j) * 3 + 1] = point_cloud_ptr->points.at(i * point_cloud_ptr->width + j).g;
Image[(i * point_cloud_ptr->width + j) * 3 + 2] = point_cloud_ptr->points.at(i * point_cloud_ptr->width + j).b;
}
}
}
int main()
{
boost::mutex new_cloud_mutex_;
PointCloudT::Ptr cloud(new PointCloudT);
bool new_cloud_available_flag = false;
std::string device_id = "";
boost::function<void(const typename PointCloudT::ConstPtr&)> f = boost::bind(&cloud_cb_, _1, cloud, &new_cloud_available_flag);
boost::shared_ptr<pcl::Grabber> grabber;
try
{
grabber.reset(new pcl::OpenNIGrabber);
cout << "Using OpenNI Device" << endl;
}
catch (pcl::IOException& e)
{
grabber.reset(new pcl::DepthSenseGrabber);
cout << "Using DepthSense Device" << endl;
}
grabber->registerCallback(f);
grabber->start();
// Image Viewer
pcl::visualization::ImageViewer Imageviewer("Image Viewer");
unsigned char* Image = new unsigned char[3*cloud->height*cloud->width];
Imageviewer.addRGBImage(Image, cloud->width, cloud->height);
// Point Cloud Viewer:
pcl::visualization::PCLVisualizer viewer("PCL Viewer");
viewer.setCameraPosition(0, 0, -2, 0, -1, 0, 0);
for (;;)
{
if (new_cloud_available_flag)
{
new_cloud_available_flag = false;
cloud_mutex.lock();
// Update Image
Imageviewer.removeLayer("rgb_image");
PointXYZRGBAtoCharArray(cloud, Image);
Imageviewer.addRGBImage(Image,cloud->width,cloud->height);
Imageviewer.spinOnce();
// Update Point Cloud
viewer.removeAllPointClouds();
viewer.addPointCloud<pcl::PointXYZRGBA>(cloud);
cloud_mutex.unlock();
viewer.spinOnce();
}
}
grabber->stop();
}
The DepthSense grabber receives two streams from the driver: depth and color. They are merged into a single point cloud with colors, which is then returned to the end user. Due to the fact that the two sensors involved (IR and color camera) have a certain displacement and different resolutions (QVGA and VGA respectively), the mapping between depth and color pixels in the streams is not trivial. In fact, for each depth/color frame the camera driver additionally produces so-called UV-map, which can be used to establish correspondences. Unfortunately, it fails to set UV-coordinates for invalid depth pixels, which makes it impossible to find corresponding RGB values for the NaN points.
I would recommend to use the DepthSense SDK directly to access raw RGB images.
I am working on a project for my computer science class where we create a photomosaic of a source image. We have been given a base image class. Along with the standard constructors, this class contains getter functions to return the private pixel array data and image height and width. We were told to create a derived class for all of the filler images, which need to be stored in a linked list. I've got the majority of the program worked out, but I don't know how to replace blocks of the source image with the pixel data from a filler image.
#include "stdafx.h" //needed for the Windows display
#include <cstdlib>
#include <cmath>
#include <string>
#include <iostream>
using namespace std;
#include "globals.h" //some global variables are included here
#include "pixel.h" //includes the pixel class for storing individual pixels
#include "image.h" //includes the image class we will be using.
#include "fillerImage.h" //includes the fillerImage
#include "fillNode.h"
#include <sstream>
image* mosaic = displayed; //displayed is the current image in the gui, mosaic is the copy that will be the photomosaic
pixel** mospix = mosaic->getPixels();
pixel** headpix = head->data->pix; //I created a public member pixel** in the filler image class with the hope that I could use it to access the private pixel data of the base image class.
int mosaicWidth = displayed->getWidth() / blockWidth * FILLER_IMAGE_WIDTH;
int mosaicHeight = displayed->getHeight() / blockHeight * FILLER_IMAGE_HEIGHT;
//mosaic->createNewImage(mosaicWidth, mosaicHeight);
for (int i = 0; i < mosaicHeight; i = i + blockHeight)
{
for (int j = 0; j < mosaicWidth; j = j + blockWidth)
{
for (int blockrow = 0; blockrow < blockHeight; blockrow++)
{
for (int blockcol = 0; blockcol < blockWidth; blockcol++)
{
mospix = headpix;
}
}
}
displayed = mosaic;
}
displayed = mosaic;
I keep running into the problem of attempting to write to protected data; how can I modify the pixel data of mosaic? I'm not allowed to edit the base image class, just the filler image class. I apologize if my post is poorly formatted, this is my first time asking for help. Thanks in advance!
EDIT: Here is the image class header. I'm not allowed to modify this in any way, and it does not contain a setter for the pixel data.
#include "globals.h"
#include "pixel.h"
using namespace std;
class image {
public:
image(); //the image constructor (initializes everything)
image(string filename); //a image constructor that directly loads an image from disk
~image(); //the image destructor (deletes the dynamically created pixel array)
void createNewImage(int width, int height); //this function deletes any current image data and creates a new blank image
//with the specified width/height and allocates the needed number of pixels
//dynamically.
bool loadImage(string filename); //load an image from the specified file path. Return true if it works, false if it is not a valid image.
//Note that we only accept images of the RGB 8bit colorspace!
void saveImage(string filename); //Save an image to the specified path
pixel** getPixels(); //return the 2-dimensional pixels array
int getWidth(); //return the width of the image
int getHeight(); //return the height of the image
void viewImage(CImage* myImage); //This function is called by the windows GUI. It returns the image in format the GUI understands.
private:
void pixelsToCImage(CImage* myImage); //this function is called internally by the image class.
//it converts our pixel object array to a standard BGR uchar array with word spacing.
//(Don't worry about what this does)
pixel** pixels; // pixel data array for image
int width, height; // stores the image dimensions
};
#endif
The only way to access to the pixels is via getPixel():
You can definitively read from it.
As this member function doesn't return a const pointer, and in absence of documentation, I assume that you can write on it as well.
With the following statement, you get access to the pixel array of mosaic.
pixel** mospix = mosaic->getPixels();
From that moment onwards, you can read/write any pixel directly by using mospix[i][j], as long as 0 <= i && i < mosaic->getHeight() && 0<=j && j<mosaic->getWidth().
There is however a serious problem in your code. In the nested loops, your inner statement is:
mospix = headpix;
This doesn't copy the current pixel as you seem to expect. It replaces the pointer that you had correctly initialized, with a copy of the pointer headpix. From then onwards, if you would access to a mospix array element, you would in reality let the picture inside mosaic unchanged, but you would access pixels in head->data !
I don't know exactly how you want to create the mosaic, but I think that there is a mismatch in the way you loop and could imagine that you wanted to say woemething like:
for (int i = 0; i < mosaic->getHeight(); i = i + blockHeight)
{
for (int blockrow = 0; blockrow < blockHeight; blockrow++)
{
for (int j = 0; j < mosaic->getWidth(); j = j + blockWidth)
{
for (int blockcol = 0; blockcol < blockWidth; blockcol++)
{
mospix[i+blockrow][j+blockcol] = headpix[blockrow][blockcol];
}
}
}
}
displayed = mosaic; // Not sure it's needed: both are pointers pointing to the same object
I have problem with low contrast image segmentation.
Task is to find surface defects. They are visible (defects are always dark areas) but the contrast of image is very low.
Below two samples.
I have tried enhance contrast and then tresholding:
Mat tmp1 = imread("C:\\framesRoi\\311.bmp",0);
stretchContrast(tmp1);
threshold(tmp1,tmp1,75,255,THRESH_BINARY);
where stretch contrast impl:
int minValue = 255, maxValue = 0;
const int l = sourceImg.cols * sourceImg.rows * sourceImg.channels();
if(sourceImg.isContinuous())
{
uchar* ptr = sourceImg.ptr<uchar>(0);
for(int i = 0; i < l; ++i)
{
if(ptr[i] < minValue)
{
minValue = ptr[i];
}
if(ptr[i] > maxValue)
{
maxValue = ptr[i];
}
}
}
cout<<"min: "<<minValue<<";"<<"max value: "<<maxValue<<endl;
const int magicThreshold = 10;
if(sourceImg.isContinuous())
{
uchar* ptr = sourceImg.ptr<uchar>(0);
for(int i = 0; i < l; ++i)
{
ptr[i] = 255 * (ptr[i]-minValue)/(maxValue - minValue);
}
}
But this approach failed. There are many false detections and not all defects are detected:
Here is zip with test frames: https://dl.dropboxusercontent.com/u/47015140/testFrames.rar
Try clustering the image by gray level using a clustering method such as kmeans. Below I've used kmeans directly on the images without any gray level transformations (using 3 clusters gave me better results). You should be able to improve results by clustering a preprocessed image using methods outlined in the comments.
Shape of the clusters may slightly vary due to the randomness of kmeans.
Now if you take connected components of the clustered image and calculate the average gray level of those regions, the defects should have a lower average than the other regions.
I did clustering part in Matlab.
im = imread('r2SOV.png');%Uy1Fq r2SOV
gr = im;
size = size(gr);
% perform closing using a 5x5 circular structuring element
sel = strel('disk', 2, 4);
mcl = imclose(gr, sel);
% cluster gray levels using kmeans: using 3 clusters
x = double(mcl(:));
idx = kmeans(x, 3);
cl = reshape(idx, size);
figure, imshow(label2rgb(cl))
As people said in your comment, you can change the brightness in a negative way and push up the contrast.
Moreover, the sharpen filter is also very useful for your case. You can do this in OpenCV.
I think you should try adaptiveThreshold function with a large window.
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int argc,char** argv )
{
Mat im = imread("c:/data/img1.png",0);
cv::namedWindow("ctrl");
int win=62;
int th=2100;
cv::createTrackbar( "win", "ctrl", &win, 500);
cv::createTrackbar( "th", "ctrl", &th, 10000);
while(true)
{
Mat thresh;
medianBlur(im,thresh,15);//helps smooth out smaller noises, which you could also remove by size instead of this way
adaptiveThreshold(thresh,thresh,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,win*2+1,( th/1000.));
imshow("thresh",thresh);
if(waitKey(1)==27)
exit(0);
}
}
all results here (http://www.datafilehost.com/d/99e3d86c) You might also want to take a look at imagej which implements a bunch of auto-threshold algorithms. I think what you need is something that takes local image information into account.
I recently installed Opencv-2.4.6
I wrote a code for bird's eye view transformation(it's not the final code).
With the earlier version of Opencv(2.4.3), it was being executed.
And now I am getting a error while running.
**error while loading shared libraries: libopencv_core.so.2.4: cannot open shared object file: No such file or directory**
There are no compilation errors.
The code is:
// This code will take undistorted images as input and give the bird's eye view using them
// First we need to calculate the homography matrix
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define heightBirdEyeView 800
#define widthBirdEyeView 800 //earlier was 300 300
using namespace cv;
using namespace std;
//global/
//camera parameters input
//resolution values
/*
float resolution_x=50, resolution_y=50;
//camera height and tilt
float height_camera = 1.25;
float tilt_camera=12;
//focal length in x and y
float focal_length_x = 354.05700;
float focal_length_y = 353.65297;*/
//intensity finding function
// find the intensity for the transformed point
/*float findintensity(float corrected_x,float corrected_y)
{
int intensity;
if((corrected_x>=1&&corrected_x<=widthBirdEyeView)&&(corrected_y>=1&&corrected_y<=heightBirdEyeView))
intensity=(1- (corrected_y-floor(corrected_y)))*(1-(corrected_x-floor(corrected_x)))*(undistor_img.at<uchar>(floor(corrected_y),floor(corrected_x)))+(1-( corrected_y-floor(corrected_y)))*(corrected_x-floor(corrected_x))*(undistor_img.at<uchar>(floor(corrected_y), ceil(corrected_x)))+(corrected_y-floor(corrected_y))*(1-(corrected_x-floor(corrected_x)))*(undistor_img.at<uchar>(ceil(corrected_y),floor(corrected_x)))+(corrected_y-floor(corrected_y))*(corrected_x-floor(corrected_x))*(undistor_img.at<uchar>(ceil(corrected_y), ceil(corrected_x)));
else
intensity=0;
return intensity;
}*/
int main(int argc, char** argv)
{
//loading the undistorted image
Mat undistor_img=imread(argv[1], 1);
namedWindow("undistorted image");
int intensity_change=0;
Mat undistor_img_hsv;
cvtColor( undistor_img,undistor_img_hsv, CV_RGB2HSV);
imshow("undistorted image", undistor_img);
imshow("hsv image",undistor_img_hsv);
cout<<"size="<<undistor_img_hsv.rows<<" "<<undistor_img_hsv.cols<<endl; // for obs7.jpg the columns are 220 and the rows are 165
//cout<<"undistorted image="<<undistor_img_hsv<<endl;
// erode the image
Mat eroded;
erode(undistor_img_hsv,eroded,Mat());
imshow("eroded",eroded);
//dilate the image
Mat dilated;
dilate(eroded,dilated,Mat());
imshow("dilated",dilated);
Mat output;
resize(undistor_img_hsv,output,cv::Size(heightBirdEyeView,widthBirdEyeView));// this will be having the orthogonal transform
int i,j;
for(i=0;i<=heightBirdEyeView;i++)
{
for(j=0;j<widthBirdEyeView;j++)
output.at<uchar>(i,j)=0;
}
imshow("output",output);
//should have size as that of height and width of the bird eye view
//camera parameters input
//resolution values
float resolution_x=50, resolution_y=50;
//camera height and tilt
float height_camera = 1.25;
float tilt_camera=12;
//focal length in x and y
float focal_length_x = 354.05700;
float focal_length_y = 353.65297;
//generate transformation matrix
float H1[3][3]={resolution_x,0,widthBirdEyeView/2+1,
0,-1*resolution_y,heightBirdEyeView,
0,0,1};
Mat transformation_matrix(3,3,CV_32FC1,H1);
cout<<"transformation matrix="<<endl<<transformation_matrix<<endl<<endl;
//generate top view matrix
float H2[3][3]={height_camera/focal_length_x,0,0,
0,0,height_camera,
0,cos(tilt_camera)/focal_length_y,sin(tilt_camera)};
Mat topview_matrix(3,3,CV_32FC1,H2);
cout<<"topview matrix="<<endl<<topview_matrix<<endl<<endl;
//generate scale matrix
float H3[3][3]={1,0,undistor_img.rows,
0,1,undistor_img.rows,
0,0,1};
Mat scale_matrix(3,3,CV_32FC1,H3);
cout<<"scale matrix="<<endl<<scale_matrix<<endl<<endl;
//generate homography matrix
Mat homography_matrix=transformation_matrix*topview_matrix/scale_matrix;
cout<<"homography matrix="<<endl<<homography_matrix<<endl<<endl;
Mat transpose_homography_matrix =homography_matrix;
Mat temp_matrix =homography_matrix;
//cout<<"temp_matrix=" <<endl<<temp_matrix<<endl<<endl;
//transpose of homography matrix
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
transpose_homography_matrix.at<float>(i,j)=temp_matrix.at<float>(j,i);
}
//cout<<"transpose homography matrix="<<endl<<transpose_homography_matrix<<endl<<endl;
float bev_zero[heightBirdEyeView][widthBirdEyeView]; //bev_zero will be the new image matrix
for(int i=0;i<heightBirdEyeView;i++)
{
for(int j=0;j<widthBirdEyeView;j++)
bev_zero[i][j]=0;
}
Mat new_point_matrix; // this 3x1 matrix will be used to give new point for all old points in old image
//(undistor_img_hsv.rows,undistor_img_hsv.cols,CV_32FC1,bev_zero);
//cout<<endl<<new_point_matrix<<endl<<endl;
//new_point_matrix=
//Mat new_point_matrix;
float corrected_x,corrected_y;
Mat old_point_matrix;
//conversion from point to its new point
for(int k=0;k<undistor_img_hsv.cols;k++)
{
for(int l=0;l<undistor_img_hsv.rows;l++)
{
float point[3][1]={k,
l,
1};
Mat old_point_matrix(3,1,CV_32FC1,point);
//get the new points for new view
//corrected_x=bev_zero[0][0]/bev_zero[2][0];
//corrected_y=bev_zero[1][0]/bev_zero[2][0];
new_point_matrix=transpose_homography_matrix*old_point_matrix;
cout<<"old point="<<old_point_matrix<<",new point="<<new_point_matrix<<endl; // every old point in the old image has got a new corresponding point
//cout<<"new x="<<corrected_x<<", new y="<<corrected_y<<endl<<endl;
//cout<<bev_zero[0][0]<<bev_zero[1][0]<<endl<<endl;
//cout<<"new x="<<new_point_matrix.at<float>(0,0)/new_point_matrix.at<float>(2,0)<<endl;
//cout<<", new y="<<new_point_matrix.at<float>(1,0)/new_point_matrix.at<float>(2,0)<<endl;x
//new_point_matrix=new_point_matrix/new_point_matrix.at<float>(2,0);
//find corrected values
corrected_x=abs(new_point_matrix.at<float>(0,0)/new_point_matrix.at<float>(2,0));
corrected_y=abs(new_point_matrix.at<float>(1,0)/new_point_matrix.at<float>(2,0));
//cout<<"point= ("<<corrected_x<<","<<corrected_y<<")"<<endl;
//cout<<"old point= ("<<k<<","<<l<<")"<<endl;
cout<<"corrected_x="<<corrected_x<<endl<<"corrected_y="<<corrected_y<<endl;
float intensity; // to store intensity values
// based on the corrected values, find out the intensity points
//cout<<findintensity(corrected_x,corrected_y)<<endl;
if((corrected_x>=1&&corrected_x<=widthBirdEyeView)&&(corrected_y>=1&&corrected_y<=heightBirdEyeView))
{
intensity_change++;
intensity=(1- (corrected_y-floor(corrected_y)))*(1-(corrected_x-floor(corrected_x)))*(undistor_img.at<uchar>(floor(corrected_y),floor(corrected_x)))+(1-( corrected_y-floor(corrected_y)))*(corrected_x-floor(corrected_x))*(undistor_img.at<uchar>(floor(corrected_y), ceil(corrected_x)))+(corrected_y-floor(corrected_y))*(1-(corrected_x-floor(corrected_x)))*(undistor_img.at<uchar>(ceil(corrected_y),floor(corrected_x)))+(corrected_y-floor(corrected_y))*(corrected_x-floor(corrected_x))*(undistor_img.at<uchar>(ceil(corrected_y), ceil(corrected_x)));
}
else
intensity=0;
cout<<"intensity="<<intensity<<endl;
//cout<<new_point_matrix<<endl;
cout<<floor(new_point_matrix.at<float>(0,0))<<endl;
cout<<int(new_point_matrix.at<float>(1,0))<<endl;
// now I just need to give this intensity value to the corresponding point for the old point
//output.at<uchar>(floor(new_point_matrix.at<float>(0,0)),floor(new_point_matrix.at<float>(1,0)))=intensity;
//cout<<"value="<<new_point_matrix.at<uchar>(0,150);
//cout<<"value21="<<undistor_img.at<uchar>(0,150);
//cout<<"pixel intensity at this point="<<new_point_matrix<<endl;
cout<<endl;
}
}
//cout<<"intensity changed "<<intensity_change<<" times."<<endl;
//imshow("output",output);
//cout<<"old point matrix="<<old_point_matrix<<endl;
//cout<<"new point matrix="<<new_point_matrix<<endl;
//cout<<"pixel intensity at this point="<<new_point_matrix<<endl; //ERROR HERE
//cout<<"changed new point="<<new_point_matrix<<endl;
/*
Mat p_new(3,1,CV_32FC1); // this will give the coordinates in the bird's eye view
float corrected_x,corrected_y;
//float Floor_corrected_y,Floor_corrected_x,Ceil_corrected_x,Ceil_corrected_y,Ratio_corrected_x,Ratio_corrected_y;
int a=0,b=0;
// counters for if and else blocks
//now we need matrix with coordinates of the image plane, to be projected
for(int p=0; p<heightBirdEyeView;p++)
{
uchar* data= undistor_img.ptr<uchar>(p);
uchar* hdata= birdeyeview_img.ptr<uchar>(p);
for(int q=0;q<widthBirdEyeView;q++)
{
//birdeyeview_img.at<cv::Vec3b>(q,p)[0]=transpose_homography_matrix*undistor_img.at<cv::Vec3b>(q,p)[0];
//birdeyeview_img.at<cv::Vec3b>(q,p)[1]=transpose_homography_matrix*undistor_img.at<cv::Vec3b>(q,p)[1];
//birdeyeview_img.at<cv::Vec3b>(q,p)[2]=transpose_homography_matrix*undistor_img.at<cv::Vec3b>(q,p)[2];
//birdeyeview_img.at<uchar>(q,p)=transpose_homography_matrix*undistor_img.at<uchar>(q,p);
//birdeyeview_img.at<uchar>(q,p)=transpose_homography_matrix*int(undistor_img.at<int>(q,p));
//cout<<transpose_homography_matrix*undistor_img.at<int>(q,p)<<endl;
int M[]={q,p,1};
Mat p_old(3,1,CV_32FC1,M); //holding the positions in undistorted image
//cout<<transpose_homography_matrix*p_old<<endl;
p_new=transpose_homography_matrix*p_old;
//cout<<endl<<p_new;
//cout<<endl<<p_new.at<float>(0,0);
//cout<<endl<<p_new[1];
//cout<<endl<<p_new[2];
//cout<<endl<<cvmGet(p_new,0,0);
corrected_x=p_new.at<float>(0,0)/p_new.at<float>(2,0);
corrected_y=p_new.at<float>(1,0)/p_new.at<float>(2,0);
//cout<<"the pixel intensity to be assigned="<<(1- (corrected_y-floor(corrected_y)))*(1-(corrected_x-floor(corrected_x)))*((int)undistor_img.at<uchar>(floor(corrected_y),floor(corrected_x)))
// +(1-( corrected_y-floor(corrected_y)))*(corrected_x-floor(corrected_x))*((int)undistor_img.at<uchar>(floor(corrected_y), ceil(corrected_x)))
// +( corrected_y-floor(corrected_y))*(1-(corrected_x-floor(corrected_x)))*((int)undistor_img.at<uchar>(ceil(corrected_y),floor(corrected_x)))
// +( corrected_y-floor(corrected_y))*(corrected_x-floor(corrected_x))*((int)undistor_img.at<uchar>(ceil(corrected_y), ceil(corrected_x)))<<endl;
//cout<<"values to be greater than 1"<<corrected_x<<","<<corrected_y<<endl;
//cout<<"those should be less than"<<undistor_img.rows<<"and"<<undistor_img.cols<<endl;
//cout<<corrected_x<<" "<<corrected_y<<endl;
if (((abs(corrected_y)>=1)&&(corrected_y<=undistor_img.rows))&&((abs(corrected_x)>=1)&&(corrected_x<=undistor_img.cols)))
{// Floor_corrected_y = floor(corrected_y);
//Ceil_corrected_y = ceil(corrected_y);
//Floor_corrected_x = floor(corrected_x);
//Ceil_corrected_x = ceil(corrected_x);
// Ratio_corrected_y = corrected_y-floor(corrected_y);
// Ratio_corrected_x = corrected_x-floor(corrected_x);
//birdeyeview_img.at<uchar>(p,q)=(1-(corrected_y-floor(corrected_y)))*(1-(corrected_x-floor(corrected_x)))*((int)undistor_img.at<uchar>(floor(corrected_y),floor(corrected_x)))
// +(1-( corrected_y-floor(corrected_y)))*(corrected_x-floor(corrected_x))*((int)undistor_img.at<uchar>(floor(corrected_y), ceil(corrected_x)))
// +( corrected_y-floor(corrected_y))*(1-(corrected_x-floor(corrected_x)))*((int)undistor_img.at<uchar>(ceil(corrected_y),floor(corrected_x)))
// +( corrected_y-floor(corrected_y))*(corrected_x-floor(corrected_x))*((int)undistor_img.at<uchar>(ceil(corrected_y), ceil(corrected_x)));
//cout<<"if read"<<endl;
//hdata[q]=(1- (corrected_y-floor(corrected_y)))*(1-(corrected_x-floor(corrected_x)))*data[q] +(1-( corrected_y-floor(corrected_y)))*(corrected_x-floor(corrected_x))*data[q] +( corrected_y-floor(corrected_y))*(1-(corrected_x-floor(corrected_x)))*data[q]+( corrected_y-floor(corrected_y))*(corrected_x-floor(corrected_x))*data[q]; //works to some extent
hdata[q]=(1- (corrected_y-floor(corrected_y)))*(1-(corrected_x-floor(corrected_x)))*undistor_img.at<uchar>(floor(corrected_y),floor(corrected_x)) +(1-( corrected_y-floor(corrected_y)))*(corrected_x-floor(corrected_x))*undistor_img.at<uchar>(floor(corrected_y), ceil(corrected_x))+( corrected_y-floor(corrected_y))*(1-(corrected_x-floor(corrected_x)))*undistor_img.at<uchar>(ceil(corrected_y),floor(corrected_x)) +( corrected_y-floor(corrected_y))*(corrected_x-floor(corrected_x))*undistor_img.at<uchar>(ceil(corrected_y), ceil(corrected_x));
a++;}
//birdeyeview_img.at<uchar>(q,p)=(1- (corrected_y-floor(corrected_y)))*(1-(corrected_x-floor(corrected_x)))*(undistor_img.at<uchar>(floor(corrected_y),floor(corrected_x)))
// +(1-( corrected_y-floor(corrected_y)))*(corrected_x-floor(corrected_x))*(undistor_img.at<uchar>(floor(corrected_y), ceil(corrected_x)))
// +(corrected_y-floor(corrected_y))*(1-(corrected_x-floor(corrected_x)))*(undistor_img.at<uchar>(ceil(corrected_y),floor(corrected_x)))
// +(corrected_y-floor(corrected_y))*(corrected_x-floor(corrected_x))*(undistor_img.at<uchar>(ceil(corrected_y), ceil(corrected_x)));
//}
else{
b++;
hdata[q]=data[q];
//birdeyeview_img.at<uchar>(p,q)=255;
//hdata[q]=undistor_img.at<uchar>(round(corrected_y),round(corrected_x));
//hdata[q]=(int)undistor_img.at<uchar>(q,p);//gives sm output
//hdata[q]= undistor_img.ptr<uchar>(p,q);
//hdata[q]= undistor_img.at<uchar>(p,q);//works to sm extent
//cout<<endl<<"pixel value"<<(int) undistor_img.at<uchar>(p,q);
//birdeyeview_img.at<uchar>(q,p)=undistor_img.at<uchar>(round(corrected_y),round(corrected_x));
}
//cout<<(int)birdeyeview_img.at<uchar>(p,q)<<endl;
//birdeyeview_img.at<uchar>(p,q)=0;}
//cout<<"else read"<<endl;}
//undistor_img.at<uchar>(p,q)=(int)undistor_img.at<uchar>(round(corrected_y),round(corrected_x));}
//birdeyeview_img.at<uchar>(p,q)=124;
//cout<<endl<<(int)undistor_img.at<uchar>(p,q);
//cout<<endl<<(int)birdeyeview_img.at<uchar>(p,q);
//cout<<"working here1"<<endl;
}
}
//flip(birdeyeview_img,birdeyeview_img,1);
// perspectiveTransform(undistor_img,birdeyeview_img ,homography_matrix);
//cout<<"bird"<<birdeyeview_img<<endl;
//cout<<"working here2"<<endl;
//cout<<birdeyeview_img<<endl;
cout<<"input channels="<<undistor_img.channels()<<endl;
//cout<<"grayscaled image channels="<<gray_undistor_img.channels()<<endl;
cout<<"output channels="<<birdeyeview_img.channels()<<endl;
cout<<"if was read"<<a <<"times"<<endl;
cout<<"else was read"<<b <<"times"<<endl;
imshow("bird's eye view image",birdeyeview_img);
cout<<"input size="<<undistor_img.rows<<"X"<<undistor_img.cols<<endl;
cout<<"result size="<<birdeyeview_img.rows<<"X"<<birdeyeview_img.cols<<endl;
//cout<<"working here3"<<endl;
*/
cvWaitKey();
}``
Can someone help what to do?
just open file called /etc/ld.so.conf.d/opencv.conf, then insert
/usr/local/opencv/
then type: sudo ldconfig
It seems you didn't install OpenCV properly, since the core library cannot be found. You have several options:
run make install (probably smth like sudo in Ubuntu will be needed) if you built the library yourself (look at the bottom of the http://docs.opencv.org/doc/tutorials/introduction/linux_install/linux_install.html)
As a quick-and-dirty hack - you can modify the LD_LIBRARY_PATH environment variable before running the executable, smth like:
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/myself/opencv/lib ./my_mighty_opencv_app
(this is one long execution command)
In my case I'm using Anaconda and the path to the opencv library is:
/home/myhome/anaconda3/envs/py27/lib
and my solution is:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/etc...
It may work for other situations. Just export LD_LIBRARY_PATH with the folder where your OpenCV libs are located.
I installed OpenCV on my Raspberrypi 3B following this tutorial and then got the same error you did. I found my solution here, by running sudo ldconfig after sudo make install.