With imgthis memory being private, you'll have to add pixel access functions. You already have getGrayscale() and setGrayscale(). You could consider, for example, defining unsigned int& operator()(int i, int j, int c). This returns a reference to a value in the image, so you can assign to it, image(4, 8, 0) = 5 would be valid. Of course you could also give it a regular function name, unsigned int& getValue(int i, int j, int c) for example; you'll still be able to assign to it: image.value(4, 8, 0) = 5.
Be very careful not to define a std::vector<std::vector<uint>> though. It is hard to initialize, and very inefficient. Just have a std::vector<uint>, and write your pixel getting/setting functions to compute the index. Outside of your class code you will never know or think about how it's implemented, you will always just use normal indexing. If you make the number of channels a parameter as well, you'll be able to use this class also for gray-scale images, which is what a lot of your code works with anyway.
Though for some advanced algorithms, it is actually really useful to do pointer arithmetic to access a pixel's neighbors. For those algorithms you will want to implement a function that returns a pointer to the first pixel (or to a pixel at a given coordinate), and you will want to have a function that says how many values to skip to get to the next pixel on the left/right (3 in your case) and bottom/top (3 * width in your case).