I am writing a simple c++ application using visual studio and opencv that stores Red, Green and Blue values from an image(named src in the code) and stores each Red, Green, Blue pixel values individually in 3 different Mat objects(named RM,BM,GM in the code). I saw this stackOverflow question
and did exactly as the first answer explained. I was able to save all the pixel values just fine, but wasn't able to change pixel values of other images because an Abort() has been called. This is the console window after I run the code.
Console Window
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include <stdio.h>
using namespace cv;
using namespace std;
int main() {
String file_name = "C:\\images\\haaand.jpg";
Mat src;
Mat RM, BM, GM;
//RM.create(src.cols, src.rows, CV_8UC(2));
//BM.create(src.cols, src.rows, CV_8UC(2));
//GM.create(src.cols, src.rows, CV_8UC(2));
Vec3b intensity;
Vec3b To[3];
src = imread(file_name);
imshow("src", src);
printf("cols:%d rows:%d \n", src.cols, src.rows);
for (int i = 0; i < src.cols; i++) {
for (int j = 0; j < src.rows; j++) {
intensity = src.at<Vec3b>(j, i);
printf("intensity:%d %d %d \n", intensity[0], intensity[1], intensity[2]);
for (int k = 0; k < 3; k++) {
//uchar bla;
//bla = intensity[k];
for (int p = 0; p < 3; p++) {
To[k][p] = intensity[k];
}
printf("(k:%d) %d %d %d\n", k, To[k][0], To[k][1], To[k][2]);
}
printf("all done\n");
BM.at<Vec3b>(j, i) = To[0];
GM.at<Vec3b>(j, i) = To[1];
RM.at<Vec3b>(j, i) = To[2];
}
}
imshow("RM", RM);
imshow("BM", BM);
imshow("GM", GM);
return 0;
}
Could anyone tell me why why this error might happen?
//RM.create(src.cols, src.rows, CV_8UC(2));
//BM.create(src.cols, src.rows, CV_8UC(2));
//GM.create(src.cols, src.rows, CV_8UC(2));
...
BM.at<Vec3b>(j, i) = To[0];
RM, BM, and GM are not setup. The debugger should show an error when you try to set BM.at<Vec3b>(j, i).
Try instead:
int main()
{
String file_name = "C:\\images\\haaand.jpg";
Mat src = imread(file_name);
Mat RM = Mat(src.size(), CV_8UC3);
Mat BM = Mat(src.size(), CV_8UC3);
Mat GM = Mat(src.size(), CV_8UC3);
Vec3b intensity;
Vec3b To[3];
for(int i = 0; i < src.cols; i++)
{
for(int j = 0; j < src.rows; j++)
{
intensity = src.at<Vec3b>(j, i);
for(int k = 0; k < 3; k++)
for(int p = 0; p < 3; p++)
To[k][p] = intensity[k];
BM.at<Vec3b>(j, i) = To[0];
GM.at<Vec3b>(j, i) = To[1];
RM.at<Vec3b>(j, i) = To[2];
}
}
imshow("src", src);
imshow("RM", RM);
imshow("BM", BM);
imshow("GM", GM);
waitKey(0);
return 0;
}
Related
I'm trying to make the Sharpening of an Image in HLS format.
I've done the Blurring correctly, but the Sharpening doesn't work.
I know the Sharpening is:
1) Blur the Image: Image -> Blurred. 2) Make Unsharp Mask: Unsharp_Mask = Image - Blurred. 3) Sharpen the Image: Sharpened = Image + Unsharp_Mask
Also I know in HLS you don't have to do this in every channel, but just in the "L" one.
I did it, but it doesn't work.
This is my code (i can't use the "code" button cause it gives me error - says that there are parts of the code that are not properly formatted as code):
// UNSHARP MASK HLS Mat* UnsharpHLS = new Mat(PaddedHLS->rows, PaddedHLS->cols, PaddedHLS->type()); Mat* SharpHLS = new Mat(PaddedHLS->rows, PaddedHLS->cols, PaddedHLS->type());
for (int i = 0; i < ImageHLS.rows; i++) {
for (int j = 0; j < ImageHLS.cols; j++)
{
UnsharpHLS->at<Vec3b>(i+1, j+1)[1] = ImageHLS.at<Vec3b>(i, j)[1] - PaddedHLS->at<Vec3b>(i + 1, j + 1)[1];
SharpHLS->at<Vec3b>(i+1, j+1)[1] = ImageHLS.at<Vec3b>(i, j)[1] + (UnsharpHLS->at<Vec3b>(i + 1, j + 1)[1]);
} }
cvtColor(*SharpHLS, Sharpened, COLOR_HLS2BGR);
Let's assume the previous part of the code works (I don't get any error and I've already tryed it), the only problem is in the mentioned code.
This is the whole code:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <cstdlib>
#include <math.h>
using namespace cv;
using namespace std;
int main()
{
// CARICAMENTO IMMAGINE
Mat Original = imread("Lena.png", IMREAD_COLOR);
// VERIFICA SE L'IMMAGINE E' STATA LETTA CORRETTAMENTE, IN CASO CONTRARIO RITORNA -1
if (Original.empty())
{
return -1;
}
// CONVERSIONE COLORI
Mat ImageHLS;
Mat ImageRGB;
Mat Blurred;
Mat Sharpened;
cvtColor(Original, ImageRGB, COLOR_BGR2RGB);
cvtColor(Original, ImageHLS, COLOR_BGR2HLS);
// CREAZIONE IMMAGINE HLS PADDED
int FilterSize = 3;
int Padding = FilterSize - 1;
Mat* PaddedHLS = new Mat(ImageHLS.rows + Padding, ImageHLS.cols + Padding, ImageHLS.type());
copyMakeBorder(ImageHLS, *PaddedHLS, Padding / 2, Padding / 2, Padding / 2, Padding / 2, BORDER_DEFAULT);
// BLURRING SU IMMAGINE HLS PADDED
Mat* Filter = new Mat(FilterSize, FilterSize, ImageHLS.type());
for (int i = 1; i < PaddedHLS->rows - 1; i++)
{
for (int j = 1; j < PaddedHLS->cols - 1; j++)
{
for (int x = 0; x < FilterSize; x++)
{
for (int y = 0; y < FilterSize; y++)
{
Filter->at<Vec3b>(x, y)[1] = PaddedHLS->at<Vec3b>(i - 1 + x, j - 1 + y)[1];
}
}
PaddedHLS->at<Vec3b>(i, j)[1] = mean(*Filter).val[1];
}
}
cvtColor(*PaddedHLS, Blurred, COLOR_HLS2BGR);
// UNSHARP MASK HLS
Mat* UnsharpHLS = new Mat(PaddedHLS->rows, PaddedHLS->cols, PaddedHLS->type());
Mat* SharpHLS = new Mat(PaddedHLS->rows, PaddedHLS->cols, PaddedHLS->type());
for (int i = 0; i < ImageHLS.rows; i++)
{
for (int j = 0; j < ImageHLS.cols; j++)
{
UnsharpHLS->at<Vec3b>(i+1, j+1)[1] = ImageHLS.at<Vec3b>(i, j)[1] - PaddedHLS->at<Vec3b>(i + 1, j + 1)[1];
SharpHLS->at<Vec3b>(i+1, j+1)[1] = ImageHLS.at<Vec3b>(i, j)[1] + (UnsharpHLS->at<Vec3b>(i + 1, j + 1)[1]);
}
}
cvtColor(*SharpHLS, Sharpened, COLOR_HLS2BGR);
// VISUALIZZAZIONE IMMAGINI
imshow("Originale", Original);
imshow("Image RGB", ImageRGB);
imshow("Image HLS", ImageHLS);
imshow("Blurred HLS", *PaddedHLS);
imshow("Blurred BGR", Blurred);
imshow("Unsharp HLS", *UnsharpHLS);
imshow("Sharpened HLS", *SharpHLS);
imshow("Sharpened BGR", Sharpened);
//CHIUDI TUTTO
waitKey(0);
destroyAllWindows();
}
I am wanting to move through an image and take a 5x5 grid centered around each pixel in the image. I then want to sum that grid and compare it to a threshold.
int main()
{
Mat element = getStructuringElement(MORPH_RECT, Size(7, 7));
Mat im = imread("blob.png", IMREAD_GRAYSCALE);
bool fromCenter = false;
namedWindow("Crop frame", WINDOW_NORMAL);
Rect2d r = selectROI("Crop frame", im, fromCenter);
im = im(r);
erode(im, im, element);
Mat clone = im;
int sectionSize = 4;
int width = im.cols - sectionSize/2;
int height = im.rows - sectionSize/2;
int sum = 0;
int counter = 0;
for (int i = sectionSize/2; i < width; i++) {
for (int j = sectionSize/2; j < height; j++) {
Rect rect = Rect(i, j, sectionSize, sectionSize);
rect -= Point(rect.width / 2, rect.height / 2);
Mat temp = im(rect);
for (int x = 0; x < temp.cols; x++) {
for (int y = 0; y < temp.rows; y++) {
int pixelValue = (int)temp.at<uchar>(y, x);
sum += pixelValue;
}
}
cout << sum << endl;
if (sum > 3800) {
clone.at<uchar>(j, i) = 255;
}
else {
clone.at<uchar>(j, i) = 0;
}
namedWindow("erode", WINDOW_NORMAL);
imshow("erode", clone);
waitKey(1);
sum = 0;
}
}
}
I am getting fluctuations in the pixel sum based on where I select my ROI in the image even when both over white space Also, my pixel sum is changing when I change the value of the clone pixel in this section of the code which I do not understand at all:
if (sum > 3800) {
clone.at<uchar>(j, i) = 255;
}
else {
clone.at<uchar>(j, i) = 0;
}
I am doing my own implementation of histogram equalization, but it produces some creepy looking images.
I got the color intensity of every pixel, then I got the probability by dividing the color intensity by the number of pixels in the picture. Then, I made a cumulative probability array that I later multiplied by 255 and floored it. This value ended up being the new color. What am I missing?
Before equalization
After equalization
My code:
void pixelFrequency(Mat img, int intensity[])
{
for (int j = 0; j < img.rows; j++)
for (int i = 0; i < img.cols; i++)
intensity[int(img.at<uchar>(j, i))]++;
}
void pixelProbability(Mat img, double probability[], int intensity[])
{
for (int i = 0; i < 256; i++)
probability[i] = intensity[i] / double(img.rows * img.cols);
}
void cumuProbability(double probability[], double cumulativeProbability[])
{
cumulativeProbability[0] = probability[0];
for (int i = 1; i < 256; i++)
cumulativeProbability[i] = probability[i] + cumulativeProbability[i - 1];
}
void histogramEqualization(Mat& img, int intensity[], double probability[], double cumulativeProbability[])
{
pixelFrequency(img, intensity);
pixelProbability(img, probability, intensity);
cumuProbability(probability, cumulativeProbability);
for (int i = 0; i < 256; i++)
cumulativeProbability[i] = floor(cumulativeProbability[i] * 255);
for (int j = 0; j < img.rows; j++)
{
for (int i = 0; i < img.cols; i++)
{
//int color = cumulativeProbability[int(img.at<uchar>(i, j))];
img.at<uchar>(j, i) = cumulativeProbability[int(img.at<uchar>(i, j))];
}
}
}
int main()
{
int intensity[256] = { 0 };
double probability[256] = { 0 };
double cumulativeProbability[256] = { 0 };
Mat img = imread("ex.jpg", CV_LOAD_IMAGE_GRAYSCALE);
histogramEqualization(img, intensity, probability, cumulativeProbability);
namedWindow("image", WINDOW_AUTOSIZE);
imshow("image", img);
waitKey(0);
return 0;
}
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).
I have copied a grayscale image into a cv::Mat1b, and I want to loop through each pixel and read and change its value. How can I do that?
My code looks like this :
cv::Mat1b newImg;
grayImg.copyTo(newImg);
for (int i = 0; i < grayImg.rows; i++) {
for (int j = 0; i < grayImg.cols; j++) {
int pixelValue = static_cast<int>(newImg.at<uchar>(i, j));
if(pixelValue > thresh)
newImg.at<int>(i,j) = 0;
else
newImg.at<int>(i, j) = 255;
}
}
But in the assignments (inside of if and else), I get the error Access violation writing location.
How do I read and write specific pixels correctly?
Thanks !
Edit
Thanks to #Miki and #Micka, this is how I solved it :
for (int i = 0; i < newImg.rows; i++) {
for (int j = 0; j < newImg.cols; j++) {
// read :
cv::Scalar intensity1 = newImg.at<uchar>(i,j);
int intensity = intensity1.val[0];
// write :
newImg(i, j) = 255;
}
}
newImg.at<int>(i,j)
should be
newImg.at<uchar>(i,j)
Because cv::Mat1b is of uchar type
i suggest :
cv::Mat1b newImg;
newImg = grayImg > thresh ;
or
cv::Mat1b newImg;
newImg = grayImg < thresh ;
also look at the OpenCV Tutorials to know how to go through each and every pixel of an image