watershed of IRM images - c++

I want to apply an algorithm of segmentation of ( watershed by markers ). I have a problem in this code. It's applied only with one image (lena.jpg)
I want to use it with irm images but it's not working.
I think that the problem is in image RGB and gray.
#include <opencv\highgui.h>
#include <opencv2\imgproc\imgproc.hpp>
#include <cstdio>
#include <iostream>
using namespace cv;
using namespace std;
static void help()
{
cout << "\nThis program demonstrates the famous watershed segmentation algorithm in OpenCV: watershed()\n"
"Usage:\n"
"./watershed [image_name -- default is ../data/fruits.jpg]\n" << endl;
cout << "Hot keys: \n"
"\tESC - quit the program\n"
"\tr - restore the original image\n"
"\tw or SPACE - run watershed segmentation algorithm\n"
"\t\t(before running it, *roughly* mark the areas to segment on the image)\n"
"\t (before that, roughly outline several markers on the image)\n";
}
Mat markerMask, img;
Point prevPt(-1, -1);
static void onMouse(int event, int x, int y, int flags, void*)
{
if (x < 0 || x >= img.cols || y < 0 || y >= img.rows)
return;
if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON))
prevPt = Point(-1, -1);
else if (event == EVENT_LBUTTONDOWN)
prevPt = Point(x, y);
else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
{
Point pt(x, y);
if (prevPt.x < 0)
prevPt = pt;
line(markerMask, prevPt, pt, Scalar::all(255), 5, 8, 0);
line(img, prevPt, pt, Scalar::all(255), 5, 8, 0);
prevPt = pt;
imshow("image", img);
}
}
int main(int argc, char** argv)
{
char* filename = argc >= 2 ? argv[1] : (char*)"samah.png";
Mat img0 = imread(filename, 1), imgGray;
if (img0.empty())
{
cout << "Couldn'g open image " << filename << ". Usage: watershed <image_name>\n";
//system("wait");
return 1;
}
help();
namedWindow("image", 1);
img0.copyTo(img);
cvtColor(img, markerMask, COLOR_BGR2GRAY);
cvtColor(markerMask, imgGray, COLOR_GRAY2BGR);
markerMask = Scalar::all(0);
imshow("image", img);
setMouseCallback("image", onMouse, 0);
for (;;)
{
int c = waitKey(0);
if ((char)c == 27)
break;
if ((char)c == 'r')
{
markerMask = Scalar::all(0);
img0.copyTo(img);
imshow("image", img);
}
if ((char)c == 'w' || (char)c == ' ')
{
int i, j, compCount = 0;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(markerMask, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
if (contours.empty())
continue;
Mat markers(markerMask.size(), CV_32S);
markers = Scalar::all(0);
int idx = 0;
for (; idx >= 0; idx = hierarchy[idx][0], compCount++)
drawContours(markers, contours, idx, Scalar::all(compCount + 1), -1, 8, hierarchy, INT_MAX);
if (compCount == 0)
continue;
vector<Vec3b> colorTab;
for (i = 0; i < compCount; i++)
{
int b = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int r = theRNG().uniform(0, 255);
colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
double t = (double)getTickCount();
watershed(img0, markers);
t = (double)getTickCount() - t;
printf("execution time = %gms\n", t*1000. / getTickFrequency());
Mat wshed(markers.size(), CV_8UC3);
// paint the watershed image
for (i = 0; i < markers.rows; i++)
for (j = 0; j < markers.cols; j++)
{
int index = markers.at<int>(i, j);
if (index == -1)
wshed.at<Vec3b>(i, j) = Vec3b(255, 255, 255);
else if (index <= 0 || index > compCount)
wshed.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
else
wshed.at<Vec3b>(i, j) = colorTab[index - 1];
}
wshed = wshed*0.5 + imgGray*0.5;
imshow("watershed transform", wshed);
}
}
system("wait");
return 0;
}

Related

Segmentation fault after upgrading to openCV 3.4.1 from 3.2

After upgrading from openCV 3.2 to openCV 3.4.1 I get Segmentation fault when running my program
Full source code below (I'm not a C expert)
running the program ./txtbin input.png output.png
Hope someone would be helpful :)
error
> Error: signal 11:
> #1 ./txtbin(_Z6bTracei+0x1c) [0x5596628d8e68]
> #2 /lib/x86_64-linux-gnu/libc.so.6(+0x33060) [0x7fa1b8481060]
> #3 /usr/local/lib/libopencv_world.so.3.4(+0xa3f7da) [0x7fa1b9ac97da]
> #4 /usr/local/lib/libopencv_world.so.3.4(+0xa2782d) [0x7fa1b9ab182d]
> #5 /usr/local/lib/libopencv_world.so.3.4(_ZN2cv7imwriteERKNS_6StringERKNS_11_InputArrayERKSt6vectorIiSaIiEE+0x8e) [0x7fa1b9ab4a4e]
> #6 ./txtbin(_ZN6Txtbin8binarizeEv+0x12d) [0x5596628d67c3]
> #7 ./txtbin(_ZN6Txtbin3runEv+0x698) [0x5596628d8c10]
> #8 ./txtbin(main+0x3fa) [0x5596628d92db]
> #9 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1) [0x7fa1b846e2e1]
input.png
txtbin.cpp
/*
* Compile
* # g++ -rdynamic -std=c++11 txtbin.cpp -o txtbin `pkg-config opencv --cflags --libs`
*
* Get opencv version
* # pkg-config --modversion opencv
*/
#include <signal.h>
#include "../backtrace/backtrace.h"
#include "txtbin.hpp"
Backtrace b;
void bTrace(int sig){
b.trace(sig);
}
void usage(const std::string VERSION){
std::cout << "txtbin: " << VERSION << "\nOpenCV: " << CV_VERSION << "\n\nUsage: txtbin input [options] output\n"
"Options:\n"
"\t-w <number> -- Set max width (keeps aspect ratio)\n"
"\t-h <number> -- Set max height (keeps aspect ratio)\n"
"\t-c -- Crop text contours\n"
"\t-r -- Rotate contents (deskew)\n"
"\t-m <number> -- Set margins (%)\n"
"\t-b <number> -- Set blockside (pixel)\n"
"\t Default: 9 pixel\n"
"\t-t <number> -- Set threshold (%)\n"
"\t Default: 85 %\n"
"\t-v -- Verbose\n" << std::endl;
}
int main(int argc, char* argv[]){
signal(SIGSEGV, &bTrace);
Txtbin a;
try{
// Parse arguments
for(int i = 1; i < argc; i++){
std::string arg = std::string(argv[i]);
if(i == 1){
a.set_input(arg);
}
else if(arg == "-w"){
a.set_width(atoi(argv[++i]));
}
else if(arg == "-h"){
a.set_height(atoi(argv[++i]));
}
else if(arg == "-c"){
a.set_crop(true);
}
else if(arg == "-r"){
a.set_rotate(true);
}
else if(arg == "-m"){
a.set_margin(atoi(argv[++i]));
}
else if(arg == "-b"){
a.set_blockside(atoi(argv[++i]));
}
else if(arg == "-t"){
a.set_threshold(atoi(argv[++i]));
}
else if(arg == "-v"){
a.set_verbose(true);
}
else if(i == argc - 1){
a.set_output(arg);
}
else{
throw std::runtime_error("Argument '"+arg+"' is invalid");
}
}
a.run();
}
catch(std::exception& e){
std::cerr << "Error: " << e.what() << "\n" << std::endl;
usage(a.VERSION);
return 1;
}
return 0;
}
txtbin.h
struct textblock{
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
};
class Txtbin{
private:
std::string input = "";
std::string output = "output.png";
int max_width = 0;
int max_height = 0;
bool is_crop = false;
bool is_rotate = false;
float margin = 0;
int blockside = 9; // set greater for larger fonts in image and vice versa
bool is_verbose = false;
float contrast = 0.01; // set smaller for lower contrast image
float thresholding = 0.85;
void binarize ();
cv::Mat src;
cv::Mat calc_block_mean_variance(cv::Mat& img);
textblock detect_text_block (bool test_output);
void downsize ();
void crop (textblock coords);
void error (const std::string& s);
public:
Txtbin();
const std::string VERSION = "0.3.6";
void set_input (const std::string& s);
void set_output (const std::string& s);
void set_height (int h);
void set_width (int w);
void set_crop (bool c);
void set_rotate (bool r);
void set_margin (float m);
void set_blockside (int b);
void set_threshold (int t);
void set_verbose (bool v);
void run ();
};
txtbin.hpp
#include <iostream>
#include <fstream>
#include <chrono>
#include <boost/algorithm/string.hpp>
#include "/usr/local/include/opencv2/opencv.hpp"
#include "txtbin.h"
Txtbin::Txtbin(){}
void Txtbin::set_input(const std::string& s){
input = s;
}
void Txtbin::set_output(const std::string& s){
output = s;
}
void Txtbin::set_height(int h){
max_height = h;
}
void Txtbin::set_width(int w){
max_width = w;
}
void Txtbin::set_crop(bool c){
is_crop = c;
}
void Txtbin::set_rotate(bool r){
is_rotate = r;
}
void Txtbin::set_margin(float m){
margin = m;
}
void Txtbin::set_blockside(int b){
blockside = b;
}
void Txtbin::set_threshold(int t){
thresholding = t / 100;
}
void Txtbin::set_verbose(bool v){
is_verbose = v;
}
void Txtbin::error(const std::string& s){
throw std::runtime_error(s);
}
void Txtbin::binarize(){
src.convertTo(src, CV_32FC1, 1.0 / 255.0);
cv::Mat res = calc_block_mean_variance(src);
imwrite(output, res * 255);
}
void Txtbin::crop(textblock coords){
if(coords.left < coords.right && coords.top < coords.bottom){
if(coords.left < 0){
coords.left = 0;
}
int crop_width = coords.right - coords.left;
int trim_width = coords.left + crop_width - src.cols;
if(trim_width > 0){
crop_width -= trim_width;
}
if(coords.top < 0){
coords.top = 0;
}
int crop_height = coords.bottom - coords.top;
int trim_height = coords.top + crop_height - src.rows;
if(trim_height > 0){
crop_height -= trim_height;
}
cv::Rect cut_rect = cv::Rect(coords.left, coords.top, crop_width, crop_height);
src = src(cut_rect);
}
else{
std::cout << "Warning: Invalid text block coordinates. Cropping is omitted!" << std::endl;
}
}
void Txtbin::downsize(){
float
width = src.cols,
height = src.rows,
scale = 0;
bool resized = false;
if(max_width > 0 && width > max_width){
scale = width / max_width;
width /= scale;
height /= scale;
resized = true;
}
if(max_height > 0 && height > max_height){
scale = height / max_height;
width /= scale;
height /= scale;
resized = true;
}
if(resized){
resize(src, src, cv::Size(round(width), round(height)));
}
}
textblock Txtbin::detect_text_block(bool test_output){
cv::Mat img = src.clone();
// downsample image and use it for processing
int multiplier = 2;
pyrDown(img, img);
textblock block;
block.left = img.cols;
block.top = img.rows;
int
rect_bottom,
rect_right;
// morphological gradient
cv::Mat grad;
cv::Mat morphKernel = getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
morphologyEx(img, grad, cv::MORPH_GRADIENT, morphKernel);
// binarize
cv::Mat bw;
threshold(grad, bw, 0.0, 255.0, cv::THRESH_BINARY | cv::THRESH_OTSU);
// connect horizontally oriented regions
cv::Mat connected;
morphKernel = getStructuringElement(cv::MORPH_RECT, cv::Size(9, 1));
morphologyEx(bw, connected, cv::MORPH_CLOSE, morphKernel);
// find contours
cv::Mat mask = cv::Mat::zeros(bw.size(), CV_8UC1);
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
cv::Scalar color = cv::Scalar(0, 255, 0);
cv::Scalar color2 = cv::Scalar(0, 0, 255);
int thickness = 2;
if(test_output){
cv::cvtColor(img, img, CV_GRAY2BGR);
}
// filter contours
if(!hierarchy.empty()){
for(int idx = 0; idx >= 0; idx = hierarchy[idx][0]){
cv::Rect rect = boundingRect(contours[idx]);
cv::Mat maskROI(mask, rect);
maskROI = cv::Scalar(0, 0, 0);
// fill the contour
drawContours(mask, contours, idx, cv::Scalar(255, 255, 255), CV_FILLED);
// ratio of non-zero pixels in the filled region
double r = (double)countNonZero(maskROI) / (rect.width * rect.height);
// assume at least 25% of the area is filled if it contains text
if (r > 0.25 &&
(rect.height > 8 && rect.width > 8) // constraints on region size
// these two conditions alone are not very robust. better to use something
//like the number of significant peaks in a horizontal projection as a third condition
){
if(test_output){
rectangle(img, rect, color, thickness);
}
//rectangle(src, cv::Rect(rect.x * multiplier, rect.y * multiplier, rect.width * multiplier, rect.height * multiplier), color, thickness);
if(rect.y < block.top){
block.top = rect.y;
}
rect_bottom = rect.y + rect.height;
if(rect_bottom > block.bottom){
block.bottom = rect_bottom;
}
if(rect.x < block.left){
block.left = rect.x;
}
rect_right = rect.x + rect.width;
if(rect_right > block.right){
block.right = rect_right;
}
}
}
}
if(test_output){
rectangle(img, cv::Point(block.left, block.top), cv::Point(block.right, block.bottom), color2, thickness);
imwrite("test_text_contours.jpg", img);
}
//rectangle(src, cv::Point(block.left * multiplier, block.top * multiplier), cv::Point(block.right * multiplier, block.bottom * multiplier), color2, thickness);
block.left *= multiplier;
block.top *= multiplier;
block.right *= multiplier;
block.bottom *= multiplier;
return block;
}
cv::Mat Txtbin::calc_block_mean_variance(cv::Mat& img){
cv::Mat res;
cv::Mat I;
img.convertTo(I, CV_32FC1);
res = cv::Mat::zeros(img.rows / blockside, img.cols / blockside, CV_32FC1);
cv::Mat inpaintmask;
cv::Mat patch;
cv::Mat small_img;
cv::Scalar m, s;
for(int i = 0; i < img.rows - blockside; i += blockside){
for(int j = 0; j < img.cols - blockside; j += blockside){
patch = I(cv::Range(i, i + blockside + 1), cv::Range(j, j + blockside + 1));
meanStdDev(patch, m, s);
if(s[0] > contrast){
res.at<float>(i / blockside, j / blockside) = m[0];
}
else{
res.at<float>(i / blockside, j / blockside) = 0;
}
}
}
resize(I, small_img, res.size());
threshold(res, inpaintmask, 0.02, 1.0, cv::THRESH_BINARY);
cv::Mat inpainted;
small_img.convertTo(small_img, CV_8UC1, 255);
inpaintmask.convertTo(inpaintmask, CV_8UC1);
inpaint(small_img, inpaintmask, inpainted, 5, cv::INPAINT_TELEA);
resize(inpainted, res, img.size());
res.convertTo(res, CV_32FC1, 1.0 / 255.0);
res = 1.0 - res;
res = img + res;
threshold(res, res, thresholding, 1, cv::THRESH_BINARY);
return res;
}
void Txtbin::run(){
// Return error if input file is not defined
if(input == ""){
error("Input file not defined");
}
// Return error if input file is not found
else{
std::ifstream stream(input.c_str());
if(!stream.good()){
error("Input file not found");
}
}
// Return error if output file is not defined
if(output == ""){
error("Output file not defined");
}
// Return error if output file is not PNG
else{
std::string output_lc = output;
boost::to_lower(output_lc);
if(output_lc.substr(output_lc.find_last_of(".") + 1) != "png"){
error("Output file must be PNG");
}
}
bool test_output = false;
auto start = std::chrono::high_resolution_clock::now();
src = cv::imread(input, CV_LOAD_IMAGE_GRAYSCALE);
if(is_crop || is_verbose){
textblock coords = detect_text_block(test_output);
if(is_verbose){
std::cout << "Image dimensions: " << src.cols << " x " << src.rows << std::endl;
std::cout << "Text block coordinates: Left|Top " << coords.left << "," << coords.top << " Right|Bottom " << coords.right << "," << coords.bottom << std::endl;
}
if(is_crop){
crop(coords);
}
}
if(margin){
int border = src.cols * margin / 100;
copyMakeBorder(src, src, border, border, border, border, cv::BORDER_CONSTANT, cv::Scalar(255, 255, 255));
}
downsize();
binarize();
auto elapsed = std::chrono::high_resolution_clock::now() - start;
if(is_verbose){
std::cout << "Execution time: " << (std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() / 1000) << " ms" << std::endl;
}
}
backtrace.h
#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>
class Backtrace {
public:
Backtrace();
void trace(int sig);
};
Backtrace::Backtrace(){}
void Backtrace::trace(int sig){
void *trace[10];
char **messages = (char **)NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 10);
messages = backtrace_symbols(trace, trace_size);
fprintf(stderr, "Error: signal %d:\n", sig);
for(i=1; i<trace_size; ++i){
fprintf(stderr, "#%d %s\n", i, messages[i]);
}
exit(1);
}
The segfault does not occur with the following implementation of Txtbin::binarize.
void Txtbin::binarize(){
src.convertTo(src, CV_32FC1, 1.0 / 255.0);
cv::Mat res = calc_block_mean_variance(src) * 255;
imwrite(output, res);
}
With the prior definition of Txtbin::binarize, cv::imwrite sees the type as _InputArray::EXPR rather than as _InputArray::MAT, and passes an uninitialized value of img_vec to cv::imwrite_. The segfault results from an attempt to dereference that uninitialized value. The _InputArray::EXPR value comes from the return value of MatExpr operator * (a cv::MatExpr) being passed to _InputArray::_InputArray.
With the modified definition of Txtbin::binarize the return value of MatExpr operator * is passed to MatExpr::operator Mat() const, which passes it to MatOp_AddEx::assign, and the value passed to _InputArray::_InputArray is a cv::Mat rather than a cv::MatExpr. In short, it seems the assignment of the return value of MatExpr operator * prevents an incorrect type conversion (cv::imwrite expects a cv::InputArray, not a cv:Mat, for its second parameter).
It appears that newer versions of opencv are not susceptible to this crash. Prior to this commit, cv::imwrite called the getMat method, and this commit restored that call as the default behavior (the else clause), as a replacement for an overly specific conditional. I confirmed that recompiling opencv with that change to cv::imwrite prevents the crash even with the prior version of Txtbin::binarize (the one in the question), and that the return value of MatExpr operator * is passed to MatExpr::operator Mat() const, as in the modified definition of Txtbin::binarize due to the assignment.
In short, you can work around issue 15545, or you can install its fix.

Debug assertion failure, "__acrt_first_block == header" when using openCV for live webcam? [duplicate]

This question already has answers here:
why opencv imshow() create a new window has the same name as namedWindow() does in Debug Mode?
(1 answer)
Debug Assertion Failed! Expression: __acrt_first_block == header
(6 answers)
Closed 4 years ago.
I'm trying to do finger recognition using opencv, which has been working correctly when simply processing one image from the capture, however after adding the while loop to have it go from single image capture to live processing, there seems to be a heap error showing. I'm currently running it on Visual Studio 2017 w/ OpenCV 3.41.
The error from the Microsoft Visual C++ Runtime Library is
Debug Assertion Failed!
File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Line: 996
Expression: __acrt_first_block == header
The code I'm using is:
#include "stdafx.h"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int myMax(int a, int b, int c);
int myMin(int a, int b, int c);
void mySkinDetect(Mat& src, Mat& dst);
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
void thresh_callback(int, void*);
int main(){
VideoCapture cap(0);
while (1) {
cap >> src;
Mat frameDest;
frameDest = Mat::zeros(src.rows, src.cols, CV_8UC1);
mySkinDetect(src, frameDest);
int erosion_size = 1;
Mat element = getStructuringElement(MORPH_RECT,
Size(2 * erosion_size + 1, 2 * erosion_size + 1),
Point(erosion_size, erosion_size));
erode(frameDest, frameDest, element);
erode(frameDest, frameDest, element);
namedWindow("Skin", WINDOW_AUTOSIZE);
imshow("Skin", frameDest);
blur(frameDest, src, Size(3, 3));
createTrackbar(" Threshold:", "Source", &thresh, max_thresh, thresh_callback);
thresh_callback(0, 0);
if (waitKey(30) == 27) { break; }
}
return(0);
}
void thresh_callback(int, void*)
{
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
threshold(src, threshold_output, thresh, 255, THRESH_BINARY);
findContours(threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
vector<vector<Point>>hull(contours.size());
vector<vector<int> > hullsI(contours.size());
vector<vector<Vec4i>>defects(contours.size());
int index = 0;
int area = 0;
for (int i = 0; i < contours.size(); i++)
{
double a = contourArea(contours[i]);
if (a>area)
{
area = a;
index = i;
}
}
for (int i = 0; i < contours.size(); i++)
{
convexHull(contours[i], hull[i], false);
convexHull(contours[i], hullsI[i], false);
if (hullsI[i].size() > 3)
{
convexityDefects(contours[i], hullsI[i], defects[i]);
}
}
Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
for (size_t i = 0; i< contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(drawing, contours, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point());
drawContours(drawing, hull, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point());
}
int fingers = 0;
if (area>50)
{
for (int j = 0; j<defects[index].size(); ++j)
{
const Vec4i& def = defects[index][j];
float depth = def[3] / 256;
if (depth > 5) // filter defects by depth
{
int start = def[0];
Point ptStart(contours[index][start]);
int end = def[1];
Point ptEnd(contours[index][end]);
int min = def[2];
Point ptFar(contours[index][min]);
line(drawing, ptStart, ptEnd, Scalar(0, 255, 0), 1);
line(drawing, ptStart, ptFar, Scalar(0, 255, 0), 1);
line(drawing, ptEnd, ptFar, Scalar(0, 255, 0), 1);
circle(drawing, ptFar, 4, Scalar(0, 255, 0), 2);
fingers += 1;
}
}
}
std::string s = std::to_string(fingers-1);
namedWindow("Hull demo", WINDOW_AUTOSIZE);
putText(drawing, "Number Fingers = "+s, Point(drawing.cols/1.5, drawing.rows / 10), FONT_HERSHEY_PLAIN, 1.2f, Scalar(200, 0, 0), 2);
imshow("Hull demo", drawing);
}
int myMax(int a, int b, int c) {
int m = a;
(void)((m < b) && (m = b));
(void)((m < c) && (m = c));
return m;
}
//Function that returns the minimum of 3 integers
int myMin(int a, int b, int c) {
int m = a;
(void)((m > b) && (m = b));
(void)((m > c) && (m = c));
return m;
}
//Function that detects whether a pixel belongs to the skin based on RGB values
void mySkinDetect(Mat& src, Mat& dst) {
//Surveys of skin color modeling and detection techniques:
//Vezhnevets, Vladimir, Vassili Sazonov, and Alla Andreeva. "A survey on pixel-based skin color detection techniques." Proc. Graphicon. Vol. 3. 2003.
//Kakumanu, Praveen, Sokratis Makrogiannis, and Nikolaos Bourbakis. "A survey of skin-color modeling and detection methods." Pattern recognition 40.3 (2007): 1106-1122.
for (int i = 0; i < src.rows; i++) {
for (int j = 0; j < src.cols; j++) {
//For each pixel, compute the average intensity of the 3 color channels
Vec3b intensity = src.at<Vec3b>(i, j); //Vec3b is a vector of 3 uchar (unsigned character)
int B = intensity[0]; int G = intensity[1]; int R = intensity[2];
if ((R > 95 && G > 40 && B > 20) && (myMax(R, G, B) - myMin(R, G, B) > 15) && (abs(R - G) > 15) && (R > G) && (R > B)) {
dst.at<uchar>(i, j) = 255;
}
}
}
}

OpenCV Error "Sizes of input arguments do not match" in my SIFT algorithm

#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <vector>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp"
#include <iomanip>
#include <fstream>
using namespace std;
using namespace cv;
/// Global Variables
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
Mat src; Mat dst_inv,dst,dest[12],dog[8],grad_x,grad_x_2,grad_x_2_1,temp,p1,p2,x_max,hess[5];
char window_name[] = "Smoothing Demo";
/// Function headers
int display_caption(const char* caption);
int display_dst(int delay);
double k,v;
int width,height,m = 0,m1 = 0,width2,height2;
int sum1,r = 10,g = 0,c = 0;
/**
* function main
*/
int main(void)
{
namedWindow(window_name, WINDOW_AUTOSIZE);
ofstream outputfile;
outputfile.open("data4.txt");
/// Load the source image
src = imread("C:/Users/Adithyaanirudhha/Documents/Visual Studio 2015/Projects/ConsoleApplication2/pa.jpg", 1);
if (display_caption("Original Image") != 0) { return 0; }
dst = src.clone();
width = src.size().width;
height = src.size().height;
Size size(height,width);
if (display_dst(DELAY_CAPTION) != 0) { return 0; }
cvtColor(src, src, CV_RGB2GRAY);
/// Applying Gaussian blur
//for(int j=0;j<4;j++)
//{
//resize(src, src, size / 2);
k = 2 ^ (1 / 2);
for(int i=0;i<3;i++)
{
//if (display_caption("Gaussian Blur") != 0) { return 0; }
GaussianBlur(src, dst, Size(), 1.6*k, 1.6*k);
if (display_dst(DELAY_BLUR*10) != 0) { return 0; }
k = k * k;
dst.copyTo(dest[m]);
//dest[m] = dst;
m++;
}
//}
Mat dog_inv;
for (int n = 0; n < 2; n++)
{
if(m1!=3 || m1 != 6 || m1 != 9)
subtract(dest[m1 + 1], dest[m1], dog[n],noArray(),-1);
}
imshow(window_name, dog[1]);
for (int i = 0; i < 2; i++)
{
Sobel(dog[1], grad_x, CV_16S, 1, 0, 3, 1, 0, BORDER_DEFAULT);
convertScaleAbs(grad_x, grad_x);
transpose(grad_x, temp);
Sobel(dog[1], grad_x_2, CV_16S, 2, 0, 3, 1, 0, BORDER_DEFAULT);
Mat tmp;
dog[1].convertTo(tmp, CV_32F);
convertScaleAbs(grad_x_2, grad_x_2);
c = invert(tmp,dog_inv, DECOMP_SVD);
//imshow(window_name,src);
Sobel(dog[1], grad_x_2_1, CV_16S, 2, 0, 3, 1, 0, BORDER_DEFAULT);
convertScaleAbs(grad_x_2_1, grad_x_2_1);
//imshow(window_name,src);
//grad_x_2_1 = grad_x_2_1.inv(CV_32F);
multiply(grad_x_2_1,grad_x,x_max, 1, 1);
multiply(temp, x_max, p1, 1, 1);
transpose(x_max,temp);
multiply(temp, grad_x_2, p2, 1, 1);
multiply(p2, x_max, p2, 1, 1);
imshow(window_name, dog[1]);
/*for (int y = 0; y < dog[i].rows; y++)
{
for (int x = 0; x < dog[i].cols; x++)
{
dog[i].at<Vec3b>(y, x) = (-1 * (p1.at<Vec3b>(y, x)) + 0.5*(p2.at<Vec3b>(y, x)) + dog[i].at<Vec3b>(y, x));
}
}*/
//imshow(window_name, dog[1]);
//imshow(window_name, src);
/* for (i = 0; i<2; i++)
{
v = determinant(dog[i]);
}
for (int h = 0; h < dog[1].rows; h++)
{
sum1 = dog[1].at<uchar>(h, h);
}
}
if ((sum1 ^ 2) / v >((r + 1) ^ 2) / r)
{
hess[g] = dog[1];
}
*/
/// Wait until user press a key
//display_caption("End: Press a key!");
//imshow(window_name, dog[1]);
//waitKey(0);
//outputfile << dog[0] << endl;
//cout << "M = " << endl << " " << dest[0] << endl << endl;
}
waitKey(0);
return 0;
}
/**
* #function display_caption
*/
int display_caption(const char* caption)
{
dst = Mat::zeros(src.size(), src.type());
putText(dst, caption,
Point(src.cols / 4, src.rows / 2),
FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255));
imshow(window_name, dst);
int c = waitKey(DELAY_CAPTION);
if (c >= 0) { return -1; }
return 0;
}
/**
* #function display_dst
*/
int display_dst(int delay)
{
imshow(window_name, dst);
int c = waitKey(delay);
if (c >= 0) { return -1; }
return 0;
}
Error is :***** VIDEOINPUT LIBRARY - 0.1995 - TFW07 *****
OpenCV Error: Sizes of input arguments do not match (The operation is neither 'array op array' (where arrays have the same size and the same number of channels)
, nor 'array op scalar', nor 'scalar op array') in cv::arithm_op, file C:\builds
lave64\win64_amdocl\master_PackSlave-win64-vc14-shared\opencv\modules\core\src\a
rithm.cpp, line 639
Press any key to continue . . .
PLease Help Thank you :)

OpenCV fisheye undistort issues

EDIT: I found the cause of the problem, the fisheye::undistortImage() function was not working correctly, I replaced it with estimateNewCameraMatrixForUndistortRectify(), initUndistortRectifyMap(), and remap() as in the original calibrate camera example. Not perfect yet but going in the right direction. Output image: http://imgur.com/a/Xm5vq
Mat output;
Mat newK;
Mat view, map1, map2;
Size newSize(1200, 1200);
Mat rview(newSize, frame.type());
//resize(rview, rview, newSize);
fisheye::estimateNewCameraMatrixForUndistortRectify(K, D, frame.size(), Matx33d::eye(), newK, 1);
fisheye::initUndistortRectifyMap(K, D, Matx33d::eye(), newK, frame.size(), CV_16SC2, map1, map2);
//fisheye::undistortImage(frame, output, K, D, identity);
remap(frame, rview, map1, map2, INTER_LINEAR);
imshow("Image View", rview);
imshow(window_name, frame);
if (waitKey(50) == 27) {
break;
}
Original post:
I'm trying to calibrate and undistort an image coming from an 180 degree fisheye USB camera. Most of this code is from existing examples that claim to be functional.
The code runs fine until fisheye::undistortImage where the output image is very distorted and centered around the top left corner of the window.
Screen shot of the "undistorted" chess board and calibration matrix outputs -
http://imgur.com/a/RTIoT
What am I missing here?
int main(int argc, char** argv) {
VideoCapture camera;
camera.open(1);
if (!camera.isOpened()) {
cout << "Failed to open camera." << std::endl;
return -1;
}
double fWidth = camera.get(CAP_PROP_FRAME_WIDTH);
double fHeight = camera.get(CAP_PROP_FRAME_HEIGHT);
cout << fWidth << std::endl;
cout << fHeight << std::endl;
/*
640 320
480 240
*/
const char* window_name = "output";
namedWindow(window_name, WINDOW_NORMAL);
Mat frame;
Size boardSize;
boardSize.width = 9;
boardSize.height = 6;
int remaining_frames = 30;
Mat K;// = Mat(3, 3, CV_64F, vK);
Mat D;
Mat identity = Mat::eye(3, 3, CV_64F);
vector<vector<Point2f> > img_points;
vector<vector<Point3f> > obj_points(1);
int sq_sz = 25;
for (int i = 0; i < boardSize.height; i++) {
for (int j = 0; j < boardSize.width; j++) {
obj_points[0].push_back(Point3f(float(j * sq_sz), float(i * sq_sz), 0));
}
}
obj_points.resize(remaining_frames, obj_points[0]);
bool found = false;
clock_t prevTimestamp = 0;
int delay = 500;
while (1) {
frame = nextFrame(camera);
bool blinkOutput = false;
if (remaining_frames > 0) {
vector<Point2f> corners;
int chessBoardFlags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE;
found = findChessboardCorners(frame, boardSize, corners, chessBoardFlags);
if (found) {
drawChessboardCorners(frame, boardSize, corners, found);
if (clock() - prevTimestamp > delay*1e-3*CLOCKS_PER_SEC) {
Mat viewGray;
cvtColor(frame, viewGray, COLOR_BGR2GRAY);
cornerSubPix(viewGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
img_points.push_back(corners);
remaining_frames--;
cout << remaining_frames << " frames to calibration." << endl;
blinkOutput = true;
prevTimestamp = clock();
}
if (remaining_frames == 0) {
cout << "Computing distortion" << endl;
int flags = 0;
flags |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
flags |= cv::fisheye::CALIB_CHECK_COND;
flags |= cv::fisheye::CALIB_FIX_SKEW;
fisheye::calibrate(obj_points, img_points, frame.size(), K, D, noArray(), noArray(), flags);
cout << "Finished computing distortion" << endl;
cout << K << endl;
cout << D << endl;
}
}
if (blinkOutput) { bitwise_not(frame, frame); }
cv::imshow(window_name, frame);
if (waitKey(50) == 27) {
break;
}
}
else {
Mat output;
fisheye::undistortImage(frame, output, K, D, identity);
cv::imshow(window_name, output);
if (waitKey(50) == 27) {
break;
}
}
}
return 0;
}

Partitions Image into boxes containing object

I have encountered a problem to partition binarized image with boxes/ subimage containing object (Note: the boxes can be irregular while the object is in circle of any other primitive shapes). This could be explained with images as below:
Figure 1: Image with circle as objects of interest
Figure 2: Image with boxes of arbitrary size containing objects of interest
Thus, any opinion that this can be done?
Since you mentioned that:
the boxes can be irregular
you can use the Voronoi diagram (computed by distanceTransform):
Code:
#include <opencv2\opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
Mat1f dist;
Mat1i labels;
distanceTransform(img, dist, labels, CV_DIST_L2, 3, DIST_LABEL_CCOMP);
// Show result
Mat1b labels1b;
labels.convertTo(labels1b, CV_8U);
normalize(labels1b, labels1b, 0, 255, NORM_MINMAX);
Mat3b res;
applyColorMap(labels1b, res, COLORMAP_JET);
res.setTo(Scalar(0,0,0), ~img);
imshow("Result", res);
waitKey();
return 0;
}
Update
If you need the boxes to be rectangles, you can look at recursive XY Cut algorithm. Here is a modified version of XY Cut algorithm, that makes the rectangles not touching the foreground objects, so that the sum of all rectangles covers the whole image area. Here I inverted the image since usually black is background, and white is foreground.
Code:
#include <opencv2\opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
vector<Rect> XYCut_projH(const Mat1b& src, Rect roi)
{
Mat1b projH;
reduce(src(roi), projH, 1, CV_REDUCE_MAX);
vector<Rect> rects;
bool bOut = true;
vector<int> coords;
coords.push_back(0);
for (int i = 0; i < projH.rows; ++i)
{
if (bOut && projH(i) > 0)
{
coords.back() = (coords.back() + i) / 2;
bOut = false;
}
else if (!bOut && projH(i) == 0)
{
coords.push_back(i);
bOut = true;
}
}
coords.front() = 0;
coords.back() = projH.rows;
if (coords.size() <= 1) return rects;
for (int i = 0; i < coords.size() - 1; ++i)
{
Rect r(0, coords[i], src.cols, coords[i + 1] - coords[i]);
r = (r + roi.tl()) & roi;
rects.push_back(r);
}
return rects;
}
vector<Rect> XYCut_projV(const Mat1b& src, Rect roi)
{
Mat1b projV;
reduce(src(roi), projV, 0, CV_REDUCE_MAX);
vector<Rect> rects;
bool bOut = true;
vector<int> coords;
coords.push_back(0);
for (int i = 0; i < projV.cols; ++i)
{
if (bOut && projV(i) > 0)
{
coords.back() = (coords.back() + i) / 2;
bOut = false;
}
else if (!bOut && projV(i) == 0)
{
coords.push_back(i);
bOut = true;
}
}
coords.front() = 0;
coords.back() = projV.cols;
if (coords.size() <= 1) return rects;
for (int i = 0; i < coords.size() - 1; ++i)
{
Rect r(coords[i], 0, coords[i + 1] - coords[i], src.rows);
r = (r + roi.tl()) & roi;
rects.push_back(r);
}
return rects;
}
void XYCut_step(const Mat1b& src, Rect roi, vector<Rect>& rects, bool bAlternate)
{
vector<Rect> step;
if (bAlternate)
{
step = XYCut_projH(src, roi);
if ((step.size() == 1) && (step[0] == roi) && (XYCut_projV(src, roi).size() == 1))
{
rects.push_back(roi);
return;
}
}
else
{
step = XYCut_projV(src, roi);
if ((step.size() == 1) && (step[0] == roi) && (XYCut_projH(src, roi).size() == 1))
{
rects.push_back(roi);
return;
}
}
for (int i = 0; i < step.size(); ++i)
{
XYCut_step(src, step[i], rects, !bAlternate);
}
}
void XYCut(const Mat1b& src, vector<Rect>& rects)
{
bool bAlternate = true;
Rect roi(0, 0, src.cols, src.rows);
XYCut_step(src, roi, rects, bAlternate);
}
int main()
{
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
// invert image, if needed
img = ~img;
// Apply (modified) XY Cut
vector<Rect> rects;
XYCut(img, rects);
// Show results
Mat3b res;
cvtColor(img, res, COLOR_GRAY2BGR);
for (int i = 0; i < rects.size(); ++i)
{
rectangle(res, rects[i], Scalar(0,255,0));
}
imshow("Result", res);
waitKey();
return 0;
}
Note that this algorithm works only if it's possible to make a cut along X or Y dimension, i.e. there is a horizontal or vertical line with all background pixels. This means that this won't work in a very cluttered image.