Currently I'm working on a non-resizable 576x512 GtkWindow,and I put a GtkGrid as its child. I want to divide the window into 9x8 areas, which means the size of each grid is 64x64.
I tried to set the height-request and width-request 64 for one of the grids, but only that grid had the right size. Then I made row_homogeneous and height_homogeneous true, but it still didn't show correctly.
So how can I let each grid 64x64?
(by the way all settings are default)
using Gtk
win=GtkWindow("Test",576,512;resizable=false,visible=true)
g=GtkGrid()
push!(win,g)
g[1,1]=GtkButton("A")
g[2,2]=GtkButton("B")
# what to do ?
showall(win)
the current main problem is the GtkWidget at (1,1) and (1,3) are neignbours instead of a space in between
In my case, the key was to resize not the grid, but its children, to the needed size. I did nothing to the grid, but make sure every button contained in the grid was 64x64 and the layout scaled appropriately. Here is the code (in C++, I don't know Julia, sorry):
#include <string>
#include <gtkmm.h>
constexpr int BTN_WIDTH = 64;
constexpr int WIN_WIDTH = 8 * 64;
constexpr int BTN_HEIGHT = 64;
constexpr int WIN_HEIGHT = 9 * 64;
class MainWindow : public Gtk::ApplicationWindow
{
public:
MainWindow();
private:
Gtk::Grid m_layout;
};
MainWindow::MainWindow()
{
set_default_size(WIN_WIDTH, WIN_HEIGHT);
set_resizable(false);
// Add items to the grid:
const int nbBtnsWide = WIN_WIDTH / BTN_WIDTH;
const int nbBtnsTall = WIN_HEIGHT / BTN_HEIGHT;
for(int row = 0; row < nbBtnsTall; ++row)
{
for(int column = 0; column < nbBtnsWide; ++column)
{
std::string btnText = "(" + std::to_string(row) + ", " + std::to_string(column) + ")";
Gtk::Widget* button = Gtk::manage(new Gtk::Button(btnText));
// Here is the key : make each button 64 x 64. This will scale the grid appropriately.
button->set_size_request(BTN_WIDTH, BTN_HEIGHT);
m_layout.attach(*button, column, row, 1, 1);
}
}
add(m_layout);
}
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
MainWindow window;
window.show_all();
return app->run(window);
}
Leaving me with this window:
Related
I have an image. Every pixel contains information about RGB intensity. Now I want to sum intenity these channels, but I also want to choose which channels intensity to sum. Straightforwad implementation of this would look like this:
int intensity(const unsiged char* pixel, bool red, bool green, bool blue){
return 0 + (red ? pixel[0] : 0) + (green ? pixel[1] : 0) + (blue ? pixel[2] : 0);
}
Because I will call this function for every pixel in image I want to discard all conditions If I can. So I guess I have to have a function for every case:
std::function<int(const unsigned char* pixel)> generateIntensityAccumulator(
const bool& accumulateRChannel,
const bool& accumulateGChannel,
const bool& accumulateBChannel)
{
if (accumulateRChannel && accumulateGChannel && accumulateBChannel){
return [](const unsigned char* pixel){
return static_cast<int>(pixel[0]) + static_cast<int>(pixel[1]) + static_cast<int>(pixel[2]);
};
}
if (!accumulateRChannel && accumulateGChannel && accumulateBChannel){
return [](const unsigned char* pixel){
return static_cast<int>(pixel[1]) + static_cast<int>(pixel[2]);
};
}
if (!accumulateRChannel && !accumulateGChannel && accumulateBChannel){
return [](const unsigned char* pixel){
return static_cast<int>(pixel[2]);
};
}
if (!accumulateRChannel && !accumulateGChannel && !accumulateBChannel){
return [](const unsigned char* pixel){
return 0;
};
}
if (accumulateRChannel && !accumulateGChannel && !accumulateBChannel){
return [](const unsigned char* pixel){
return static_cast<int>(pixel[0]);
};
}
if (!accumulateRChannel && accumulateGChannel && !accumulateBChannel){
return [](const unsigned char* pixel){
return static_cast<int>(pixel[1]);
};
}
if (accumulateRChannel && !accumulateGChannel && accumulateBChannel){
return [](const unsigned char* pixel){
return static_cast<int>(pixel[0]) + static_cast<int>(pixel[2]);
};
}
if (accumulateRChannel && accumulateGChannel && !accumulateBChannel){
return [](const unsigned char* pixel){
return static_cast<int>(pixel[0]) + static_cast<int>(pixel[1]);
};
}
}
Now I can use this generator before entering image loop and use function without any conditions:
...
auto accumulator = generateIntensityAccumulator(true, false, true);
for(auto pixel : pixels){
auto intensity = accumulator(pixel);
}
...
But it is a lot of writting for such simple task and I have a feeling that there is a better way to accomplish this: for example make compiler to do a dirty work for me and generate all above cases. Can someone point me in the right direction?
Using a std::function like this will cost you dear, because you dont let a chance for the compiler to optimize by inlining what it can.
What you are trying to do is a good job for templates. And since you use integral numbers, the expression itself may be optimized away, sparing you the need to write a specialization of each version. Look at this example :
#include <array>
#include <chrono>
#include <iostream>
#include <random>
#include <vector>
template <bool AccumulateR, bool AccumulateG, bool AccumulateB>
inline int accumulate(const unsigned char *pixel) {
static constexpr int enableR = static_cast<int>(AccumulateR);
static constexpr int enableG = static_cast<int>(AccumulateG);
static constexpr int enableB = static_cast<int>(AccumulateB);
return enableR * static_cast<int>(pixel[0]) +
enableG * static_cast<int>(pixel[1]) +
enableB * static_cast<int>(pixel[2]);
}
int main(void) {
std::vector<std::array<unsigned char, 3>> pixels(
1e7, std::array<unsigned char, 3>{0, 0, 0});
// Fill up with randomness
std::random_device rd;
std::uniform_int_distribution<unsigned char> dist(0, 255);
for (auto &pixel : pixels) {
pixel[0] = dist(rd);
pixel[1] = dist(rd);
pixel[2] = dist(rd);
}
// Measure perf
using namespace std::chrono;
auto t1 = high_resolution_clock::now();
int sum1 = 0;
for (auto const &pixel : pixels)
sum1 += accumulate<true, true, true>(pixel.data());
auto t2 = high_resolution_clock::now();
int sum2 = 0;
for (auto const &pixel : pixels)
sum2 += accumulate<false, true, false>(pixel.data());
auto t3 = high_resolution_clock::now();
std::cout << "Sum 1 " << sum1 << " in "
<< duration_cast<milliseconds>(t2 - t1).count() << "ms\n";
std::cout << "Sum 2 " << sum2 << " in "
<< duration_cast<milliseconds>(t3 - t2).count() << "ms\n";
}
Compiled with Clang 3.9 with -O2, yields this result on my CPU:
Sum 1 -470682949 in 7ms
Sum 2 1275037960 in 2ms
Please notice the fact that we have an overflow here, you may need to use something bigger than an int. A uint64_t might do. If you inspect assembly code, you will see that the two versions of the function are inlined and optimized differently.
First things first. Don't write a std::function that takes a single pixel; write one that takes a contiguous range of pixels (a scanline of pixels).
Second, you want to write a template version of intensity:
template<bool red, bool green, bool blue>
int intensity(const unsiged char* pixel){
return (red ? pixel[0] : 0) + (green ? pixel[1] : 0) + (blue ? pixel[2] : 0);
}
pretty simple, eh? That will optimize down to your hand-crafted version.
template<std::size_t index>
int intensity(const unsiged char* pixel){
return intensity< index&1, index&2, index&4 >(pixel);
}
this one maps from the bits of index to which of the intensity<bool, bool, bool> to call. Now for the scanline version:
template<std::size_t index, std::size_t pixel_stride=3>
int sum_intensity(const unsiged char* pixel, std::size_t count){
int value = 0;
while(count--) {
value += intensity<index>(pixel);
pixel += pixel_stride;
}
return value;
}
We can now generate our scanline intensity calculator:
int(*)( const unsigned char* pel, std::size_t pixels )
scanline_intensity(bool red, bool green, bool blue) {
static const auto table[] = {
sum_intensity<0b000>, sum_intensity<0b001>,
sum_intensity<0b010>, sum_intensity<0b011>,
sum_intensity<0b100>, sum_intensity<0b101>,
sum_intensity<0b110>, sum_intensity<0b111>,
};
std::size_t index = red + green*2 + blue*4;
return sum_intensity[index];
}
and done.
These techniques can be made generic, but you don't need the generic ones.
If your pixel stride is not 3 (say there is an alpha channel), sum_intensity needs to be passed it (as a template parameter ideally).
I have a class Grid declared as follows:
Grid.h
#ifndef DATATEST_GRID_H
#define DATATEST_GRID_H
#include <memory>
#include <vector>
#include "Position.h"
class Grid
{
public:
Grid(int length_x, int length_y);
~Grid();
Position *at(int x, int y);
void printGrid();
private:
int length_x, length_y;
std::vector<std::unique_ptr<Position>> grid;
};
#endif
Its most important member variable is the vector<unique_ptr<Position>>, which I'm using to simulate a 2-dimensional array whose size is determined at runtime. The class declaration for the Position is as follows:
Position.h
#ifndef DATATEST_POSITION_H
#define DATATEST_POSITION_H
#include <memory>
#include <string>
class Position {
public:
Position(int x, int y);
~Position();
std::string toString();
int getX() { return x; };
int getY() { return y; };
private:
int x, y;
};
#endif
In the Grid's constructor, I want to create the desired number of Positions and add them to the vector<unique_ptr<Position>>.
Grid.cpp
#include "Grid.h"
#include <iostream>
#include <memory>
#include <vector>
#include "Position.h"
Grid::Grid(int length_x, int length_y)
: length_x(length_x), length_y(length_y)
{
grid.resize(length_x * length_y);
for (int x = 0; x < length_x; x++) {
for (int y = 0; y < length_y; y++) {
/* Option 1 */
std::unique_ptr<Position> temp = std::make_unique<Position>(x, y);
grid.push_back(std::move(temp));
/* Option 2 */
// std::unique_ptr<Position> temp = std::make_unique<Position>(x, y);
// grid.emplace_back(std::move(temp));
/* Option 3 */
// grid.push_back(std::make_unique<Position>(x, y));
/* Option 4 */
// grid.emplace_back(std::make_unique<Position>(x, y));
}
}
}
Grid::~Grid()
{
grid.clear();
}
Position *Grid::at(int x, int y)
{
if (x < 0 || x >= length_x || y < 0 || y >= length_y) {
return nullptr;
}
else {
return grid.at(x * (length_y) + y).get();
}
}
void Grid::printGrid()
{
for (int i = 0; i < grid.size(); i++) {
std::cout << grid.at(i)->toString() << std::endl;
}
}
I'm testing access by calling Position::toString for each unique_ptr<Position> and printing the result to the console.
Position.cpp
#include "Position.h"
#include <string>
Position::Position(int x, int y)
: x(x), y(y)
{
}
Position::~Position()
{
}
std::string Position::toString()
{
return "Position(" + std::to_string(x) + ", " + std::to_string(y) + ")";
}
And finally, the main function:
Main.cpp
#include "Grid.h"
#include "Position.h"
int main()
{
Grid g(2, 2);
g.printGrid();
return 0;
}
No matter which way I populate the vector<unique_ptr<Position>>, I always get the following error:
First-chance exception at 0x0087D8A3 in CombatSim.exe: 0xC0000005: Access violation reading location 0x00000000.
Unhandled exception at 0x0087D8A3 in CombatSim.exe: 0xC0000005: Access violation reading location 0x00000000.
As far as I know, I could have one of four problems:
1) I'm adding the unique_ptr to the created Position object to the vector incorrectly
2) I'm using the wrong method to dynamically create Position objects.
3) All of the above.
4) Something I don't know about.
Use std::vector::reserve(n) instead of std::vector::resize(n) if you are going to push_back those n elements afterwards.
resize will fill the vector with initialized objects, so the vector.size() will be n after that.
reserve will just reserve enough space for all n element, but will not insert any objects.
It seems that resizing the grid will first insert length_x * length_y unique pointers that all point to 0. Your push_back should be fine but your real elements start at position length_x * length_y in the vector. I think removing the line
grid.resize(length_x * length_y);
should solve the problem. Maybe someone else can explain why this happens.
I am using the Mat_<float> aque(3,3);
aque << .240 , .640 , .450
,0,0,0
,0,0,0
I want to turn it in to light blue , how I can adjust these values ? I want to know the function of these three values .240 , .640 , .450 in matrix , I know these all are presenting blue color but what are their functionalities what they all 3 values present ?
just go and do your own experiments ?
int f[9] = {24,64,45,0,0,0,0,0,0}; // initial trackbar pos
Mat filt(3,3,CV_32F);
Mat img;
void onTrack(int,void*)
{
float *p = filt.ptr<float>(0);
for ( int i=0; i<9; i++ )
{
p[i] = float(f[i]) / 100; // get it back to [0..1] range for the transform matrix
}
Mat out;
cv::transform(img,out,filt);
imshow("result",out);
}
int main( int argc, const char** argv )
{
img = imread("lena.jpg");
namedWindow("result",0);
namedWindow("sliders",0);
createTrackbar("1","sliders",&f[0],100,onTrack);
createTrackbar("2","sliders",&f[1],100,onTrack);
createTrackbar("3","sliders",&f[2],100,onTrack);
createTrackbar("4","sliders",&f[3],100,onTrack);
createTrackbar("5","sliders",&f[4],100,onTrack);
createTrackbar("6","sliders",&f[5],100,onTrack);
createTrackbar("7","sliders",&f[6],100,onTrack);
createTrackbar("8","sliders",&f[7],100,onTrack);
createTrackbar("9","sliders",&f[8],100,onTrack);
onTrack(0,0);
waitKey();
cerr << filt << endl;
return 0;
}
if you 're happy with the results, just divide each slider value by 100, and compose a filter matrix from that.
I have a classic problem about the output of sobel filter using CUDA.
this is a main class (main.cpp)
/*main class */
int main(int argc, char** argv)
{
IplImage* image_source = cvLoadImage("test.jpg",
CV_LOAD_IMAGE_GRAYSCALE);
IplImage* image_input = cvCreateImage(cvGetSize(image_source),
IPL_DEPTH_8U,image_source->nChannels);
IplImage* image_output = cvCreateImage(cvGetSize(image_source),
IPL_DEPTH_8U,image_source->nChannels);
/* Convert from IplImage tofloat */
cvConvert(image_source,image_input);
unsigned char *h_out = (unsigned char*)image_output->imageData;
unsigned char *h_in = (unsigned char*)image_input->imageData;
width = image_input->width;
height = image_input->height;
widthStep = image_input->widthStep;
sobel_parallel(h_in, h_out, width, height, widthStep);
cvShowImage( "CPU", image_output );
cvReleaseImage( &image_output );
waitKey(0);
}
And this is the CUDA file (kernel_gpu.cu)
__global__ void kernel ( unsigned char *d_in , unsigned char *d_out , int width ,
int height, int widthStep ) {
int col = blockIdx . x * blockDim . x + threadIdx . x ;
int row = blockIdx . y * blockDim . y + threadIdx . y ;
int dx [3][3] = { -1 , 0 , 1 ,
-2 , 0 , 2 ,
-1 , 0 , 1};
int dy [3][3] = {1 ,2 ,1 ,
0 ,0 ,0 ,
-1 , -2 , -1};
int s;
if( col < width && row < height)
{
int i = row;
int j = col;
// apply kernel in X direction
int sum_x=0;
for(int m=-1; m<=1; m++)
for(int n=-1; n<=1; n++)
{
s=d_in[(i+m)*widthStep+j+n]; // get the (i,j) pixel value
sum_x+=s*dx[m+1][n+1];
}
// apply kernel in Y direction
int sum_y=0;
for(int m=-1; m<=1; m++)
for(int n=-1; n<=1; n++)
{
s=d_in[(i+m)*widthStep+j+n]; // get the (i,j) pixel value
sum_y+=s*dy[m+1][n+1];
}
int sum=abs(sum_x)+abs(sum_y);
if (sum>255)
sum=255;
d_out[i*widthStep+j]=sum; // set the (i,j) pixel value
}
}
// Kernel Calling Function
extern "C" void sobel_parallel( unsigned char* h_in, unsigned char* h_out,
int rows, int cols, int widthStep){
unsigned char* d_in;
unsigned char* d_out;
cudaMalloc((void**) &d_in, rows*cols);
cudaMalloc((void**) &d_out, rows*cols);
cudaMemcpy(d_in, h_in, rows*cols*sizeof( unsigned char), cudaMemcpyHostToDevice);
dim3 block (16,16);
dim3 grid ((rows * cols) / 256.0);
kernel<<<grid,block>>>(d_in, d_out, rows, cols, widthStep);
cudaMemcpy(h_out, d_out, rows*cols*sizeof( unsigned char), cudaMemcpyDeviceToHost);
cudaFree(d_in);
cudaFree(d_out);
}
Error :
the result image does not appear in their entirety, only part of the image.
Why is the result(GPU) like this?? (I tried to make CPU computation using the same function and no problem).
You are creating 1 Dimensional grid, while using 2D indexing inside the kernel which will cover only the x direction and only the top 16 rows of the image will be filtered (because the height of the block is 16).
dim3 grid ((rows * cols) / 256.0); //This is incorrect in current case
Consider creating 2 dimensional grid, so that it spans all the rows of the image.
dim3 grid ((cols + 15)/16, (rows + 15)/16);
Check the width and widthStep variables to see if they are actually equal or not because in your sobel_parallel function you are implicitly assuming this (which might not be true since your data is aligned). If this is not true the code
cudaMalloc((void**) &d_in, rows*cols);
will actually allocate less memory than necessary and hence you will only process part of your image. It would be better to use
cudaMalloc((void**) &d_in, rows*widthStep);
And of course adjust the rest of your code as necessary.
You are also calling
void sobel_parallel( unsigned char* h_in, unsigned char* h_out,
int rows, int cols, int widthStep)
with
sobel_parallel(h_in, h_out, width, height, widthStep);
which exchanges rows with cols and this is again exchanged when you are calling your kernel. This will cause a problem when you use the above suggestion.
I was wondering how can I insert an empty space in the string text (defined in
char *text = argv[1];)
For example, if a write:
./mar "Hello how are you"
I would like to see/
Hello how are you Hello how are you Hello how are you Hello how are you
and not
Hello how are youHello how are youHello how are youHello how are youHello how are you
scrolling horizontally in the cli.
The code is:
/*mar.c*/
#include <curses.h>
#include <unistd.h> // For sleep()
#include <string.h> // For strlen()
#include <stdlib.h> // For malloc()
#include <sys/select.h>
int main(int argc, char* argv[])
{
char *text = argv[1];
char *scroll;
int text_length;
int i,p, max_x, max_y;
// Get text length
text_length = strlen(text);
// Initialize screen for ncurses
initscr();
// Don't show cursor
curs_set(0);
// Clear the screen
clear();
// Get terminal dimensions
getmaxyx(stdscr, max_y, max_x);
scroll = malloc(2 * max_x + 1);
for (i=0; i< 2*max_x; i++) {
getmaxyx(stdscr, max_y, max_x);
scroll[i] = text[i % text_length];
}
scroll[2*max_x - 1]='\0';
// Scroll text back across the screen
p=0;
do{
getmaxyx(stdscr, max_y, max_x);
mvaddnstr(0,0,&scroll[p%max_x], max_x);
refresh();
usleep(40000);
p=p+1;
// Execute while none key is pressed
}while (!kbhit());
endwin();
return 0;
}
int kbhit(void)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec=0;
tv.tv_usec=0;
FD_ZERO(&read_fd);
FD_SET(0,&read_fd);
if(select(1, &read_fd, NULL, NULL, &tv) == -1)
return 0;
if(FD_ISSET(0,&read_fd))
return 1;
return 0;
}
You need to allocate a new char array whose length is 2 bytes greater than the length of the argument string (so that there's room both for the space and for the null terminator). Then, call strcpy to copy the argument string into the new array, overwrite the second-to-last index with a space and put a null terminator into the last index.