Opencv: EM algorithm training slowly - c++

I am trying to use opencv EM algorithm library.
I tried some example about EM algorithm such like this and this first, but I got the same problem in these code. It take me lots of time in EM training step.
This is my testing code for image segmentation from this website:
#include <opencv2/opencv.hpp>
#include <opencv2/legacy/legacy.hpp>
using namespace std;
using namespace cv;
Mat asSamplesVectors(Mat& img);
/** #function main */
int main(int argc, char** argv)
{
Mat image; int no_of_clusters = 2;
image = imread("images/flower.jpg");
Mat samples = asSamplesVectors(image);
cout << "Starting EM training" << endl;
EM em(no_of_clusters);
em.train(samples);
cout << "Finished training EM" << endl;
vector<Mat> segmented;
for (int i = 0; i < no_of_clusters; i++)
segmented.push_back(Mat::zeros(image.rows, image.cols, CV_8UC3));
int index = 0;
for (int y = 0; y < image.rows; y++) {
for (int x = 0; x < image.cols; x++) {
int result = em.predict(samples.row(index++))[1];
segmented[result].at<Point3i>(y, x, 0) = image.at<Point3i>(y, x, 0);
}
}
imshow("result", samples);
return(0);
}
Mat asSamplesVectors(Mat& img) {
Mat float_img;
img.convertTo(float_img, CV_32F);
Mat samples(img.rows * img.cols, 3, CV_32FC1);
/* Flatten */
int index = 0;
for (int y = 0; y < img.rows; y++) {
Vec3f* row = float_img.ptr<Vec3f>(y);
for (int x = 0; x < img.cols; x++)
samples.at<Vec3f>(index++, 0) = row[x];
}
return samples;
}
I test in VS2013, opencv 2.4.9 and opencv 2.4.11.
This is my testing image.
In this code, it show me the error message.
The error step is segmented[result].at<Point3i>(y, x, 0) = image.at<Point3i>(y, x, 0);
My first question is: why the EM training so slowly. Is it normally?
Second question is: what's wrong with my code error and is there any better example to let me know the usage of EM?

I found the answer of first problem, my testing image is too large to training.
The size of training image is need to scale smaller.
I use this article to modify pixel and it works.

Related

Coding dedicated function Average Filter to color Images C++ OpenCV

So basically, I have to code my own function in C++ with OpenCV, that will apply average filter on both gray and color images.
The function returns a Mat Object, have a mat Object and the size of the average filter (3 for 3x3 matrix of filtering for example).
I did this for the moment, it doesn't work, and I don't know how to extend it to color.
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
Mat filtrageMoyen(Mat image, int tailleZonage) {
Mat imageRetour;
imageRetour = image.clone();
Scalar intensite = 0;
int cadrillage = tailleZonage / 2;
int valeurMoyenne = 0;
for (size_t x = 0; x < imageRetour.rows; x++)
{
for (size_t y = 0; y < imageRetour.cols; y++)
{
for (size_t xZonage = 0; xZonage < cadrillage; xZonage++)
{
for (size_t yZonage = 0; yZonage < cadrillage; yZonage++)
{
valeurMoyenne += (image.at<unsigned char>(x+xZonage, y + yZonage));
}
}
imageRetour.at<unsigned char>(x, y) = valeurMoyenne;
valeurMoyenne = 0;
}
}
return imageRetour;
}
int main() {
Mat img;
string filename = "imageRickRoll.png";
img = imread(filename, cv::IMREAD_GRAYSCALE);
imshow("Image filtree", filtrageMoyen(img, 5));
waitKey(0);
return 0;
}

Create a single image from images array

Hi I'm trying to create a single image from multiple images in opencv.
images I use are the same size.
what I do is reshaping them to single line and then try to merge them together with my new image.
I create new image with size of 2 images and pass the array but I recieve error EXC_BAD_ACCESS(code=1, address = ..)
note: sizes of images are correct
size of single image : [170569 x 1]
size of new_image : [170569 x 2]
my code is below.
thank you
int main(){
Mat image[2];
image[0]= imread("image1.jpg",0);
image[1]= imread("image2.jpg",0);
image[0] = image[0].reshape(0, 1); //SINGLE LINE
image[1] = image[1].reshape(0, 1); //SINGLE LINE
int size = sizeof(image)/sizeof(Mat);
Mat new_image(image[0].cols,size,CV_32FC1,image);
}
Mat new_image;
vconcat(image[0],image[1],new_image);
If I understand well than you need to concatenate 2 image of same size into one Mat. I wrote this a very quick code to perform this task.
U can change the argument to the function to be a pointer and add other handlers to care about the variant size image.
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
cv::Mat cvConcatenateMat(const cv::Mat &image1, const cv::Mat &image2, bool isCol CV_DEFAULT(true)){
if (isCol) {
cv::Mat mergeMat = cv::Mat(image1.rows, image1.cols + image2.cols, image1.type());
for (int j = 0; j < image1.rows; j++) {
for (int i = 0; i < image1.cols; i++) {
mergeMat.at<cv::Vec3b>(j,i) = image1.at<cv::Vec3b>(j,i);
}
for (int i = image1.cols; i < mergeMat.cols; i++) {
mergeMat.at<cv::Vec3b>(j,i) = image2.at<cv::Vec3b>(j,i);
}
}
return mergeMat;
} else {
cv::Mat mergeMat = cv::Mat(image1.rows + image2.rows, image1.cols, image1.type());
for (int j = 0; j < image1.cols; j++) {
for (int i = 0; i < image1.rows; i++) {
mergeMat.at<cv::Vec3b>(i,j) = image1.at<cv::Vec3b>(i,j);
}
for (int i = image1.rows; i < mergeMat.rows; i++) {
mergeMat.at<cv::Vec3b>(i,j) = image2.at<cv::Vec3b>(i-image1.rows,j);
}
}
return mergeMat;
}
}
int main(int argc, const char * argv[]) {
cv::Mat image1 = cv::imread("img1.jpg");
cv::Mat image2 = cv::imread("img2.jpg");
cv::resize(image2, image2, image1.size());
cv::Mat outImage = cvConcatenateMat(image1, image2, false);
cv::imshow("out image", outImage);
cv::waitKey(0);
return 0;
}

Embed watermark using dct on image opencv

I wants to embed watermark into an image using dct with c++ and opencv.
I split image into 8x8 block and apply dct to each block.
Now I don't know what to do next, Can anyone give me some hint or help me?
Here is my work so far.
int main() {
Mat originalImage;
originalImage = imread("image.jpg");
if( !originalImage.data )
{
std::cout<< "Error loading original image!"<<std::endl;
return -1;
}
cout << "Working on image from image.jpg" << endl;
/// Create Windows
namedWindow("Original", 1);
imshow( "Original", originalImage );
int x = 0; int y = 0;
moveWindow("Original", x, y);
imshow("Original", originalImage);
x += 100; y += 100;
int width = originalImage.size().width;
int height = originalImage.size().width;
cout << "Original image Width x Height is " << width << "x" << height << endl;
// Leave original alone, work on a copy
Mat dctImage = originalImage.clone();
// Step through the copied image with rectangles size 8x8
// For each block, split into planes, do dct, and merge back
// into the block. (This will affect the image from
// which the block is selected each time.)
for (int i = 0; i < height; i += 8)
{
for (int j = 0; j < width; j+= 8)
{
Mat block = dctImage(Rect(i, j, 8, 8));
vector<Mat> planes;
split(block, planes);
vector<Mat> outplanes(planes.size());
for (size_t k = 0; k < planes.size(); k++)
{
planes[k].convertTo(planes[k], CV_32FC1);
dct(planes[k], outplanes[k]);
outplanes[k].convertTo(outplanes[k], CV_8UC1);
}
merge(outplanes, block);
}
}
namedWindow("dctBlockImage");
moveWindow("dctBlockImage", x, y);
imshow("dctBlockImage", dctImage);
x += 100; y += 100;
waitKey();
destroyAllWindows();
return 0;
}

OpenCV counting number of pixels in a horizontal line

I wish to find number of white pixels in every row of binary image. And if that count is greater than 90, I wish to delete the entire row by changing each pixel value in that row to 0. The code that I wrote is not working. And apparently, I am getting the same binary image at output.
Please help me out in fixing the problem. BTW, am using openCV 2.0.
using namespace std;
double a = 15;
double b = 255;
Mat I1;
int main(int argv, char **argc)
{
cv: Mat I = imread("abc.bmp");
if (I.empty())
{
std::cout << "!!! Failed imread(): image not found" << std::endl;
}
threshold(I, I1, a, b, THRESH_BINARY);
int r = I.rows;
int c = I.cols;
for (int j = 0; j < r; j++)
{
int count = 0;
for (int i = 0; i < c; i++)
{
if (I1.at<uchar>(j, i) == 255)
count = count + 1;
}
if (count > 90)
{
for (int i = 0; i < c; i++)
I1.at<uchar>(j, i) = 0;
}
}
namedWindow("Display window", 0);// Create a window for display.
imshow("Display window", I1);
waitKey(0);
return 0;
}
By default imread returns 3 channel BGR image. If you want to load grayscale/binary image use cv::IMREAD_GRAYSCALE parameter:
cv::Mat I = cv::imread("abc.bmp", cv::IMREAD_GRAYSCALE);

C++ Stretching an equalized image

From an (2)equalized image I have to create a (3).
Original image: http://i.imgur.com/X5MKF6z.jpg
Equalized image : http://i.imgur.com/oFBVUJp.png
Equalized and Stretch image: http://i.imgur.com/V7jeaRQ.png
With OpenCV I could have used equalizeHist() that does both equalization and stretching.
So without using OPENCV, how can I do stretching from an equalization image. The equalization part is done below.
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv/highgui.h>
#include <cstring>
using std::cout;
using std::cin;
using std::endl;
using namespace cv;
void imhist(Mat image, int histogram[])
{
// initialize all intensity values to 0
for (int i = 0; i < 256; i++)
{
histogram[i] = 0;
}
// calculate the no of pixels for each intensity values
for (int y = 0; y < image.rows; y++)
for (int x = 0; x < image.cols; x++)
histogram[(int)image.at<uchar>(y, x)]++;
}
void cumhist(int histogram[], int cumhistogram[])
{
cumhistogram[0] = histogram[0];
for (int i = 1; i < 256; i++)
{
cumhistogram[i] = histogram[i] + cumhistogram[i - 1];
}
}
int main()
{
// Load the image
Mat image = imread("y1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
// Generate the histogram
int histogram[256];
imhist(image, histogram);
// Caluculate the size of image
int size = image.rows * image.cols;
float alpha = 255.0 / size;
// Calculate the probability of each intensity
float PrRk[256];
for (int i = 0; i < 256; i++)
{
PrRk[i] = (double)histogram[i] / size;
}
// Generate cumulative frequency histogram
int cumhistogram[256];
cumhist(histogram, cumhistogram);
// Scale the histogram
int Sk[256];
for (int i = 0; i < 256; i++)
{
Sk[i] = cvRound((double)cumhistogram[i] * alpha);
}
// Generate the equlized image
Mat new_image = image.clone();
for (int y = 0; y < image.rows; y++)
for (int x = 0; x < image.cols; x++)
new_image.at<uchar>(y, x) = saturate_cast<uchar>(Sk[image.at<uchar>(y, x)]);
//////////////////////////////////////////
// // Generate the histogram stretched image
Mat str_image = new_image.clone();
//for (int a = 0; a < str_image.rows; a++)
// for (int b = 0; b < str_image.cols; b++)
// Display the original Image
namedWindow("Original Image");
imshow("Original Image", image);
// Display equilized image
namedWindow("Equalized Image");
imshow("Equalized Image", new_image);
waitKey();
return 0;
}
The normal way to do this is to find your darkest pixel, and your brightest. You can do this in a singe loop iterating over all your pixels, pseudo-code like this:
darkest=pixel[0,0] // assume first pixel is darkest for now, and overwrite later
brightest=pixel[0,0] // assume first pixel is lightest for now, and overwrite later
for all pixels
if this pixel < darkest
darkest = this pixel
else if this pixel > brightest
brightest = this pixel
endif
end for
Simple enough. So, let's say the darkest and brightest are 80 and 220 respectively. Now you need to stretch this range 80..220 onto the full range 0..255.
So you subtract 80 from every pixel in your image to shift down to zero at the left end of the histogram, so your range is now 0..140. So now you need to multiply every pixel by 255/140 to stretch the right end out to 255. Of course, you can do both pieces of arithmetic in a single pass over your pixel array.
for all pixels
newvalue = int((current value - darkest)*255/(brightest-darkest))
end for