Sobel algorithm without library, greyscale output - c++

I'm trying to get this output b&w positives and negatives and gray neutrals
But instead I'm getting this B&W only
I'm not sure what to change about my code.
Mat sobelX(const cv::Mat &m){
Mat im = m.clone();
int gx, mag;
for (int i = 0; i < m.rows; i++){
for (int j = 0; j < m.cols;
//find x gradient
gx = m.at<uchar>(i-1, j-1)
+ 2*m.at<uchar>(i, j-1)
+ m.at<uchar>(i+1, j-1)
- m.at<uchar>(i-1, j+1)
- 2*m.at<uchar>(i, j+1)
- m.at<uchar>(i+1, j+1);
mag = sqrt(gx*gx);
if (mag < 0) {
mag = 0; //set to black
}
else if (mag > 255) {
mag = 255; //set to white
}
im.at<uchar>(i, j) = mag;
}
}
return im;
}
Thanks.

Related

Warp Image by Diagonal Sine Wave

I'm trying to warp colour image using sin function in OpenCV and I was successful in doing so. However, how can I make a 'diagonal' warping using sine wave?
My code is this:
Mat result = src.clone();
for (int i = 0; i < src.rows; i++) { // to y
for (int j = 0; j < src.cols; j++) { // to x
for (int ch = 0; ch < 3; ch++) { // each colour
int offset_x = 0;
int offset_y = (int)(25.0 * sin(3.14 * j / 150));
if (i + offset_y < src.rows) {
result.at<Vec3b>(i, j)[ch] = src.at<Vec3b>((i + offset_y) % src.rows, j)[ch];
}
else
result.at<Vec3b>(i, j)[ch] = 0.0;
}
}
}
imshow("result", result);
How can I do this? Not drawing a sine graph, but warping an image.
Solved this! Several times ago, I've received a message by someone who told me that the image is stolen. It was from Google, actually, but I've deleted it to fulfill not to cause any situations. Thx!
I think it should look like this:
void deform()
{
float alpha = 45 * CV_PI / 180.0; // wave direction
float ox = cos(alpha);
float oy = sin(alpha);
cv::Mat src = cv::imread("F:/ImagesForTest/lena.jpg");
for (int i = 0; i < src.rows; i+=8)
{
cv::line(src, cv::Point(i, 0), cv::Point(i, src.rows),cv::Scalar(255,255,255));
}
for (int j = 0; j < src.cols; j += 8)
{
cv::line(src, cv::Point(0,j), cv::Point(src.cols,j), cv::Scalar(255, 255, 255));
}
cv::Mat result = src.clone();
for (int i = 0; i < src.rows; i++)
{ // to y
for (int j = 0; j < src.cols; j++)
{ // to x
float t =(i * oy)+ (j * ox); // wave parameter
for (int ch = 0; ch < 3; ch++)
{ // each colour
int offset_x =ox* (int)(25.0 * (sin(3.14 * t/ 150)));
int offset_y =oy* (int)(25.0 * (sin(3.14 * t / 150)));
if (i + offset_y < src.rows && j + offset_x < src.rows && i + offset_y >=0 && j + offset_x>=0)
{
result.at<cv::Vec3b>(i, j)[ch] = src.at<cv::Vec3b>(i + offset_y, j + offset_x )[ch];
}
else
result.at<cv::Vec3b>(i, j)[ch] = 0.0;
}
}
}
cv:: imshow("result", result);
cv::imwrite("result.jpg", result);
cv::waitKey();
}
The result:
BTW, may be better to use cv::remap ?

normalize histogram in c++ - function normalize in openCV

I need to normalize the histogram of an image f which mean to applicated an transformation of histogram from image in order to extend the range of value of f to all available values.
the norm(fmin) = Vmin ( minimal value we want to reach) and normal(fmin) = Vmax ( maximal value we want to reach)
I have this formula too
the goal is to have the same result that the function normalize which openCV gives.
Mat normalize(Mat image, float minValue, float maxValue)
{
Mat res = image.clone();
assert(minValue <= maxValue);
float Fmax = 0;
float Fmin = 0;
for(int i = 0; i < res.rows; i++)
{
for(int j = 0; j < res.cols; j++)
{
float x = res.at<float>(i,j);
if(i < minValue)
{
Fmin = i;
}
if( i > maxValue)
{
Fmax = i;
}
res.at<float>(i,j) = (x - Fmin) * ((maxValue - minValue) / (Fmax - Fmin)) + minValue;
}
}
return res;
}
I have this error : !!! Warning, saved image values not between 0 and 1.
!!! Warning, saved image values not between 0 and 1.
I think I didn't understand how to calculate fmin/ fmax
So, as I explained in my comment, there are some mistakes, here's the corrected version. You need to run the double loop twice, once to find the min-max, and a second time to apply the formula. There were also errors in the comparisons:
cv::Mat normalize(cv::Mat image, float minValue, float maxValue)
{
cv::Mat res = image.clone();
assert(minValue <= maxValue);
// 1) find min and max values
float Fmax = 0.0f;
float Fmin = 1.0f; // set it to 1, not 0
for (int i = 0; i < res.rows; i++)
{
float* pixels = res.ptr<float>(i); // this is quicker
for (int j = 0; j < res.cols; j++)
{
float x = pixels[j];
if (x < Fmin) // compare x and Fmin, not i and minValue
{
Fmin = x;
}
if (x > Fmax) // compare x and Fmax, not i and maxValue
{
Fmax = x;
}
}
}
// 1 color image => don't normalize + avoid crash
if (Fmin >= Fmax)
return res;
// 2) normalize using your formula
for (int i = 0; i < res.rows; i++)
{
float* pixels = res.ptr<float>(i);
for (int j = 0; j < res.cols; j++)
{
pixels[j] = (pixels[j] - Fmin) * ((maxValue - minValue) / (Fmax - Fmin)) + minValue;
}
}
return res;
}
If your source image is a grayscale image in 8 bit, you can convert it like that:
cv::Mat floatImage;
grayImage.convertTo(floatImage, CV_32F, 1.0 / 255, 0);
floatImage = normalize(floatImage, 0, 1.0f);
floatImage.convertTo(grayImage, CV_8UC1, 255.0, 0);
Also, if you use cv::minMaxLoc, your normalize function can be made shorter =>
cv::Mat normalize(cv::Mat image, float minValue, float maxValue)
{
cv::Mat res = image.clone();
assert(minValue <= maxValue);
// 1) find min and max values
double Fmax;
double Fmin;
cv::minMaxLoc(image, &Fmin, &Fmax);
if (Fmin >= Fmax)
return res;
// 2) normalize using your formula
for (int i = 0; i < res.rows; i++)
{
float* pixels = res.ptr<float>(i);
for (int j = 0; j < res.cols; j++)
{
pixels[j] = (pixels[j] - Fmin) * ((maxValue - minValue) / (Fmax - Fmin)) + minValue;
}
}
return res;
}

Canny Edge Detection- Non Maximum Surpression Implementation

I am trying to implement the Canny edge detection algorithm from scratch with the help of OpenCV. I am facing a problem implementing the Non-Maximum Suppression step which helps to thin the edges.
My logic is to first compute the intensity gradient vector, then group it in either 0,45,90,135 degrees direction and then try to find local maxima. The method to find this local maxima is by making sure that current pixel is greater than succeeding and preceeding pixel in same direction. If not, I assign value of zero to this pixel. Using this logic, I'm still not able to thin the edges. I feel the error is when I'm computing the intensity gradient vector for each pixel.
Here is my code-
#include <iostream>
#include <bits/stdc++.h>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/objdetect/objdetect.hpp>
#include <math.h>
using namespace cv;
using namespace std;
int main()
{
// Reading image
Mat img = imread("1.jpg");
// Displaying image
//imshow("Original Image",img);
//waitKey(0);
// Converting to grayscale
Mat img_gray,image_gray;
cvtColor(img,image_gray,CV_RGB2GRAY);
GaussianBlur( image_gray, img_gray, Size(15,15), 3, 3);
// Displaying grayscale image
imshow("Original Image",img_gray);
waitKey(0);
int cols = img_gray.cols;
int rows = img_gray.rows;
// Creating sobel operator in x direction
int sobel_x[3][3] = {-1,0,1,-2,0,2,-1,0,1};
// Creating sobel operator in y direction
int sobel_y[3][3] = {1,2,1,0,0,0,-1,-2,-1};
int radius = 1;
// Handle border issues
Mat _src;
copyMakeBorder(img_gray, _src, radius, radius, radius, radius, BORDER_REFLECT101);
// Create output matrix
Mat gradient_x = img_gray.clone();
Mat gradient_y = img_gray.clone();
Mat gradient_f = img_gray.clone();
Mat gradient_mag = img_gray.clone();
// Conrrelation loop in x direction
// Iterate on image
for (int r = radius; r < _src.rows - radius; ++r)
{
for (int c = radius; c < _src.cols - radius; ++c)
{
int s = 0;
// Iterate on kernel
for (int i = -radius; i <= radius; ++i)
{
for (int j = -radius; j <= radius; ++j)
{
s += _src.at<uchar>(r + i, c + j) * sobel_x[i + radius][j + radius];
}
}
gradient_x.at<uchar>(r - radius, c - radius) = s/8;
/*if(s>200)
gradient.at<uchar>(r - radius, c - radius) = 255;
else
gradient.at<uchar>(r - radius, c - radius) = 0;
*/
}
}
// Conrrelation loop in y direction
// Iterate on image
for (int r = radius; r < _src.rows - radius; ++r)
{
for (int c = radius; c < _src.cols - radius; ++c)
{
int s = 0;
// Iterate on kernel
for (int i = -radius; i <= radius; ++i)
{
for (int j = -radius; j <= radius; ++j)
{
s += _src.at<uchar>(r + i, c + j) * sobel_y[i + radius][j + radius];
}
}
gradient_y.at<uchar>(r - radius, c - radius) = s/8;
/*if(s>200)
gradient.at<uchar>(r - radius, c - radius) = 255;
else
gradient.at<uchar>(r - radius, c - radius) = 0;
*/
}
}
///cout<<endl<<"max:"<<max;
//cout<<img_gray.rows;
//cout<<endl<<_src.rows;
cout<<endl<<gradient_x.rows;
cout<<endl<<gradient_y.rows;
cout<<endl<<gradient_f.rows<<gradient_f.cols;
//Calculating gradient magnitude
for(int i=0; i<gradient_mag.rows; i++)
{
for(int j=0; j<gradient_mag.cols; j++)
{
gradient_mag.at<uchar>(i,j) = sqrt( pow(gradient_x.at<uchar>(i,j),2) + pow(gradient_y.at<uchar>(i,j),2) );
if(gradient_mag.at<uchar>(i,j) >250)
gradient_f.at<uchar>(i,j) = 255;
else
gradient_f.at<uchar>(i,j) = 0;
}
}
/*
imshow("grad x",gradient_x);
waitKey(0);
imshow("grad y",gradient_y);
waitKey(0);
*/
imshow("grad magnitude",gradient_f);
waitKey(0);
int max=0;
// Performing Non-Maximum Surpression
float theta; // Calculate intensity gradient vector theta=atan2(Gy,Gx);
Mat nonMaxSupp= Mat(gradient_mag.rows-2, gradient_mag.cols-2, CV_8UC1); //CV_8UC1 is 8-bit single channel image i.e grayscale
for(int i=1; i<gradient_x.rows-1; i++)
{
for(int j=1; j<gradient_x.cols-1; j++)
{
//if(gradient_x.at<uchar>(i,j) ==0) //Arctan Fix
// theta = 90;
//else
theta = atan2(gradient_y.at<uchar>(i,j),gradient_x.at<uchar>(i,j))*(180/3.14);
//theta = atan(gradient_y.at<uchar>(i,j)/gradient_x.at<uchar>(i,j))*(180/3.14);
//cout<<theta<<endl;
//if(theta>max)
// max=theta;
nonMaxSupp.at<uchar>(i-1, j-1) = gradient_mag.at<uchar>(i,j);
// For horizontal edge
if(((-22.5 < theta) && (theta <= 22.5)) || ((157.5 < theta) && (theta <= -157.5)))
{
if ((gradient_mag.at<uchar>(i,j) < gradient_mag.at<uchar>(i,j+1)) || (gradient_mag.at<uchar>(i,j) < gradient_mag.at<uchar>(i,j-1)))
nonMaxSupp.at<uchar>(i-1, j-1) = 0;
}
//For vertical edge
if (((-112.5 < theta) && (theta <= -67.5)) || ((67.5 < theta) && (theta <= 112.5)))
{
if ((gradient_mag.at<uchar>(i,j) < gradient_mag.at<uchar>(i+1,j)) || (gradient_mag.at<uchar>(i,j) < gradient_mag.at<uchar>(i-1,j)))
nonMaxSupp.at<uchar>(i-1, j-1) = 0;
}
// For 135 degree or -45 degree edge
if (((-67.5 < theta) && (theta <= -22.5)) || ((112.5 < theta) && (theta <= 157.5)))
{
if ((gradient_mag.at<uchar>(i,j) < gradient_mag.at<uchar>(i-1,j+1)) || (gradient_mag.at<uchar>(i,j) < gradient_mag.at<uchar>(i+1,j-1)))
nonMaxSupp.at<uchar>(i-1, j-1) = 0;
}
// For 45 Degree Edge
if (((-157.5 < theta) && (theta <= -112.5)) || ((22.5 < theta) && (theta <= 67.5)))
{
if ((gradient_mag.at<uchar>(i,j) < gradient_mag.at<uchar>(i+1,j+1)) || (gradient_mag.at<uchar>(i,j) < gradient_mag.at<uchar>(i-1,j-1)))
nonMaxSupp.at<uchar>(i-1, j-1) = 0;
}
}
}
//cout<<endl<<"max"<<max;
imshow("Non-Maximum Surpression",nonMaxSupp);
waitKey(0);
return 0;
}

Setting transparency in OpenCV not working

I am setting transparency for a four channeled Mat like this (Based on some calculations). But when I am showing the image the on window there is no change happening for the Image. Any help would be a great support.
void feather_touch(Rect enclosingRect, Mat frame){
Point center(frame.size().width * 0.5, frame.size().height * 0.5);
int inclussive_circle_radius = (sqrt((frame.cols * frame.cols + frame.rows * frame.rows))) / 2;
for(int i = 0; i < frame.rows; i++){
for(int j = 0; j < frame.cols; j++){
Point point(i, j);
if(!inRect(point, enclosingRect)){
Vec4b channels = frame.at<Vec4b>(i, j);
int dx = center.x - point.x;
int dy = center.y - point.y;
int dist = sqrt((dx * dx) + (dy * dy));
float alpha = (float)dist/(float)inclussive_circle_radius;
int a = (int)((1 - alpha) * 255);
frame.at<Vec4b>(i, j)[3] = a;
}
}
}
}
bool inRect(cv::Point p,Rect rect) {
return p.x >= rect.x && p.x <= (rect.x + rect.width) && p.y >= rect.y && p.y <= (rect.y + rect.height);
}
I got the answer though: imshow in OpenCV doesn't support transparency.I replaced it by using addWeighted functionality. Now my function look like this:
float alpha = ((float)dist/(float)inclussive_circle_radius);
//int a = (int)((1 - alpha) * 255);
//frame.at<Vec4b>(i, j)[3] = a;
Rect rect(j, i, 1, 1);
Mat mat = frame(rect);
Mat sub = layer(rect);
if(dist > (enclosingRect.width*0.5)){
addWeighted(mat, alpha, sub, 1 - alpha, 0, mat);
mat.copyTo(frame(rect));
}else{
sub.copyTo(frame(rect));
}

Histogram of oriented gradiants

For a project I'm writing some code to compute the HoG of some images, but I'm stuck with the fact that my orientations are only between 0 ~ 90 degrees, while using the atan2 function.
I'm guessing that this problem occurs due to the filter2D function of OpenCV but I'm not sure if this is the reason or that I'm doing something else wrong:
Vector<Vector<Mat_<float>>> HoG(Mat image) {
Mat img_x;
Mat img_y;
IplImage img = image;
Mat kern_x = (Mat_<char>(1, 3) << -1, 0, 1);
Mat kern_y = (Mat_<char>(3, 1) << -1, 0, 1);
filter2D(image, img_x, image.depth(), kern_x);
filter2D(image, img_y, image.depth(), kern_y);
Vector<Vector<Mat_<float>>> histograms;
for(int y = 0; y < image.rows - size; y += size) {
Vector<Mat_<float>> temp_hist;
for(int x = 0; x < image.cols - size; x += size) {
float total_mag = 0;
Mat hist = Mat::zeros(1, 8, CV_32FC1);
for(int i = y; i < y + size; ++i) {
for(int j = x; j < x + size; ++j) {
float grad_x = (float)img_x.at<uchar>(i, j);
float grad_y = (float)img_y.at<uchar>(i, j);
double ori = myatan2(grad_x, grad_y);
float mag = sqrt(pow(grad_x, 2) + pow(grad_y, 2));
int bin = round(ori/45);
hist.at<float>(0, (bin - 1 < 0 ? 7 : bin - 1)) += - (float)(ori - ((round(ori/45) - 1) * 45.0 + 22.5)) / 45.0f;
hist.at<float>(0, bin) += -(float)(ori - ((round(ori/45) - 1) * 45.0 + 22.5)) / 45.0f;
total_mag += mag;
}
}
// Normalize the histogram
for(int i = 0; i < 8; ++i) {
hist.at<float>(0, i) = hist.at<float>(0, i) / total_mag;
}
temp_hist.push_back(hist);
}
histograms.push_back(temp_hist);
}
return histograms;
}
If you have any other tips to increase a speed-up in my code or something else that is also welcome of course.
I notice this:
float grad_x = (float)img_x.at<uchar>(i, j);
float grad_y = (float)img_y.at<uchar>(i, j);
You seem to be using uchar. Should this not be char?