Please mark this answer as correct if it satisfies your question. :)
I load a flipped version of your input image:
My output looks like this, where the blue circles show branching:
As you can see, it works quite well now.
My C++ code (now followed by a Python code) is:
#include <opencv2/opencv.hpp>
using namespace cv;
#pragma comment(lib, "opencv_world331.lib")
#include <iostream>
#include <vector>
using namespace std;
int main(void)
{
Mat frame = imread("sparks.png");
if (frame.empty())
{
cout << "Error loading image file" << endl;
return -1;
}
Mat colour_frame = frame.clone();
cvtColor(frame, frame, CV_BGR2GRAY);
threshold(frame, frame, 127, 255, THRESH_BINARY);
vector<Point2i> branch_locations;
// Start with the second column
for (int i = 1; i < frame.cols; i++)
{
bool lit = false;
vector<int> begin_black_regions;
vector<int> end_black_regions;
// Start with the first row
if (255 == frame.at<unsigned char>(0, i))
{
lit = true;
}
else
{
lit = false;
begin_black_regions.push_back(0);
}
// Start with the second row
for (int j = 1; j < frame.rows - 1; j++)
{
if (255 == frame.at<unsigned char>(j, i) && lit == false)
{
lit = true;
end_black_regions.push_back(j - 1);
}
else if (0 == frame.at<unsigned char>(j, i) && lit == true)
{
lit = false;
begin_black_regions.push_back(j);
}
}
// End with the last row
if (0 == frame.at<unsigned char>(frame.rows - 1, i) && lit == false)
{
end_black_regions.push_back(frame.rows - 1);
}
else if (0 == frame.at<unsigned char>(frame.rows - 1, i) && lit == true)
{
begin_black_regions.push_back(frame.rows - 1);
end_black_regions.push_back(frame.rows - 1);
}
else if (255 == frame.at<unsigned char>(frame.rows - 1, i) && lit == false)
{
end_black_regions.push_back(frame.rows - 2);
}
if(begin_black_regions.size() != end_black_regions.size())
cout << begin_black_regions.size() << " " << end_black_regions.size() << endl;
// for each black region begin/end pair
for (size_t k = 0; k < begin_black_regions.size(); k++)
{
bool found_branch = true;
for (int l = begin_black_regions[k]; l <= end_black_regions[k]; l++)
{
if (0 == frame.at<unsigned char>(l, i - 1))
{
found_branch = false;
break;
}
}
if (found_branch == true)
{
Point2i location(i - 1, begin_black_regions[k]);
branch_locations.push_back(location);
}
}
}
for (size_t i = 0; i < branch_locations.size(); i++)
circle(colour_frame, branch_locations[i], 2, Scalar(255, 127, 0), 2);
imshow("frame", colour_frame);
waitKey();
return 0;
}
The Python code is:
import cv2
import numpy
frame = cv2.imread('sparks.png')
if frame is None:
print('Error loading image')
exit()
colour_frame = frame
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
ret, frame = cv2.threshold(frame, 127, 255, cv2.THRESH_BINARY)
rows = frame.shape[0]
cols = frame.shape[1]
branch_locations = []
# start with second column
for i in range(1, cols):
lit = False
begin_black_regions = []
end_black_regions = []
# start with first row
if 255 == frame[0, i]:
lit = True
else:
lit = False
begin_black_regions.append(0)
# start with second row
for j in range(1, rows - 1):
if 255 == frame[j, i] and lit == False:
lit = True
end_black_regions.append(j - 1)
elif 0 == frame[j, i] and lit == True:
lit = False
begin_black_regions.append(j)
# end with last row
if 0 == frame[rows - 1, i] and lit == False:
end_black_regions.append(rows - 1)
elif 0 == frame[rows - 1, i] and lit == True:
begin_black_regions.append(rows - 1)
end_black_regions.append(rows - 1 ...
(more)
seing, what you tried so far (as in: code) and maybe an example image would be helpful
I'm just echoing berak... please put up some code, or at least some images. Marking the bifurcation (or trifurcation or whatnot) points sounds like a very fun project to work on. I would give it my best attempt, if only you could post some images.
Actually, I don’t really need pictures... I’ll just use the bifurcation diagram of the logistic function as sample input.
So I added a picture. Hope, this will help.
Holy cow that’s a lot of sparks. :)
So, it's taken that the motion of the sparks is to the left, correct? On second thought, I flipped the image horizontally, so the sparks move right.
Right now my main attack will be to cut the image into 1xheight strips, and do an edge detection along the 1D strip. The edge count determines the number of sparks per line. A change in sparks per line means sparks dying or sparks tri/etc/bifurcating.
I wouldn't get your hopes up too much. I'll try my best.
I put the code, incomplete as it is, up at: https://github.com/sjhalayka/opencv_s...
When the code is complete, I will answer your question.
Thank you so much. I will have look and try to comprehend, what you did.
I guess the problem here is, that lines of seperate sparks can cross, without being split, isnt it?
I'm currently stuck in design mode again, which I do before I switch to code mode. What do you think would be the best way to determine if there is branching, and if so, where that branching occurs? Any thoughts?
I also didn't use an edge detection algorithm. I just used the threshold function to convert the grayscale image into a binary image, then did the spark count per vertical line based on that input. If you look at the left-most vertical column in your sample image, you will see that there are 16 "sparks" (white regions). Count them if you like. The right-most vertical column in your sample image has only 4 "sparks" (white regions), so it's much easier (for a human) to count.
Perhaps the solution also relies on counting the black regions? I'm not sure yet.
And whatever the solution is, it will be able to handle bifurcations, trifurcations, and whatnot. The solution will also likely rely on the the distinction between white and black.