# Hough Transform 2D Circles Image Filter GetCircles patch.

**URL:** <https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350>\
**Category:** Algorithms\
**Created:** [October 24, 2017, 5:26pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350 "2017-10-24T17:26:37Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [October 24, 2017, 5:26pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/1 "2017-10-24T17:26:37Z")

</div>

I’m currently trying out itk::HoughTransform2DCirclesImageFilter::GetCircles(n), and while I get quite promising results, there still appears room for improvement of the code.

Here’s my first patch for this function:  
"PERF: Break out of loop as soon as requested number of circles is found"  
[http://review.source.kitware.com/#/c/22744/](http://review.source.kitware.com/#/c/22744/)

Please have a look! What do you think?

Link to HoughTransform2DCirclesImageFilter::GetCircles(n):

> <https://github.com/InsightSoftwareConsortium/ITK/blob/v4.12.2/Modules/Filtering/ImageFeature/include/itkHoughTransform2DCirclesImageFilter.hxx#L178>

---

<div class="post-metadata">

**Author:** ![matt.mccormick](https://discourse.itk.org/user_avatar/discourse.itk.org/matt.mccormick/32/7_2.png) [@matt.mccormick](https://discourse.itk.org/u/matt.mccormick)\
**Post date:** [October 24, 2017, 5:50pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/2 "2017-10-24T17:50:19Z")

</div>

These performance improvement contributions are appreciated! The patch looks good. Thank you @Niels_Dekker 👏

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [October 24, 2017, 6:03pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/3 "2017-10-24T18:03:57Z")

</div>

Thank you Matt! Actually I see two more possible performance improvements in the very same function!

1. At the beginning it makes a copy of GetOutput(0) to outputImage. Looks like an expensive operation that should not be necessary, as outputImage is only used as an input to DiscreteGaussianImageFilter. I think it might as well pass the result of GetOutput(0) directly to the filter, right?

2. It uses MinimumMaximumImageCalculator to find the maximum pixel value of postProcessImage, but then it iterates another time over the pixel data to find the actual index of that pixel. I think it should use MinimumMaximumImageCalculator::GetIndexOfMaximum(), right?

Hope you can help me to get these two PERF issues fixed as well 🙂

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [October 24, 2017, 6:24pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/4 "2017-10-24T18:24:57Z")

</div>

1 . The output image is copied because the the `GetCircles` method may be called multiple times and we don’t want to modify the output image. I would look into changing the loop to use [ImageAlgorithm::Copy](https://itk.org/Doxygen/html/structitk_1_1ImageAlgorithm.html#a5ec5bcac992cb3b1302840636530ba20). It should be much faster.

1. The GetIndexOfMaximum seems reasonable.

2. You may want to look into the SmoothingRecursiveGaussianImageFilter over the Discrete.

---

<div class="post-metadata">

**Author:** ![matt.mccormick](https://discourse.itk.org/user_avatar/discourse.itk.org/matt.mccormick/32/7_2.png) [@matt.mccormick](https://discourse.itk.org/u/matt.mccormick)\
**Post date:** [October 24, 2017, 6:42pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/5 "2017-10-24T18:42:41Z")

</div>

> [@Niels\_Dekker](#):
>
> At the beginning it makes a copy of GetOutput(0) to outputImage. Looks like an expensive operation that should not be necessary, as outputImage is only used as an input to DiscreteGaussianImageFilter. I think it might as well pass the result of GetOutput(0) directly to the filter, right?

Good catch. Yes, that looks right. One side effect we have to watch out for is unintended / unnecessary pipeline updates. Adding the [PipelineMonitorImageFilter](https://itk.org/ITKExamples/src/Core/Common/StreamAPipeline/Documentation.html) before the filter will hep to verify that unintended behavior does not occur.

> [@Niels\_Dekker](#):
>
> It uses MinimumMaximumImageCalculator to find the maximum pixel value of postProcessImage, but then it iterates another time over the pixel data to find the actual index of that pixel. I think it should use MinimumMaximumImageCalculator::GetIndexOfMaximum(), right?

Sounds good.

Thanks for contributing these improvements! ☀

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [October 24, 2017, 6:54pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/6 "2017-10-24T18:54:48Z")

</div>

> [@matt.mccormick](#):
>
> Good catch. Yes, that looks right. One side effect we have to watch out for is unintended / unnecessary pipeline updates. Adding the [PipelineMonitorImageFilter](https://itk.org/ITKExamples/src/Core/Common/StreamAPipeline/Documentation.html) before the filter will hep to verify that unintended behavior does not occur.
> 
> Thanks for contributing these improvements! ☀

Ahh! Using `Image::Graft` is a way to isolate an internal pipeline in a filter from the external execution. You can look at the [CompositeFilterExample](https://github.com/InsightSoftwareConsortium/ITK/blob/3c91dd5cc6ef1a477321aef8d76b318321594412/Examples/Filtering/CompositeFilterExample.cxx#L214-L215) for reference. I believe you could replace the copy with something like:

```auto
outputImage->Graft(this->GetOutput(0));

```

The `outputImage` will still be a new image, but it will reference the same data as `GetOutput(0)`.

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [October 25, 2017, 2:50pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/7 "2017-10-25T14:50:52Z")

</div>

Thank you very much for getting my first GetCircles patch [http://review.source.kitware.com/#/c/22744/](http://review.source.kitware.com/#/c/22744/) (breaking out of loop as soon as requested number of circles is found) onto the master branch!

@matt.mccormick, @blowekamp, I just submitted my second patch, which avoids expensive copying of the image data from HoughTransform2DCirclesImageFilter::GetOutput(0): [http://review.source.kitware.com/#/c/22747/](http://review.source.kitware.com/#/c/22747/)

I still think it should be OK to directly use the data from GetOutput(0) as input to the DiscreteGaussianImageFilter, especially because the input parameter is a pointer-to-const, and the instance of DiscreteGaussianImageFilter is only a locally used object. When the function has returned, the DiscreteGaussianImageFilter and its output are gone. Right?

Do you still think that something like Image::Graft or PipelineMonitorImageFilter should be added in this specific case? I’m asking also because the unit tests now just appear to run successfully. Can you show me a test that would fail on my patch at [http://review.source.kitware.com/#/c/22747/](http://review.source.kitware.com/#/c/22747/) ?

---

<div class="post-metadata">

**Author:** ![matt.mccormick](https://discourse.itk.org/user_avatar/discourse.itk.org/matt.mccormick/32/7_2.png) [@matt.mccormick](https://discourse.itk.org/u/matt.mccormick)\
**Post date:** [October 25, 2017, 3:23pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/8 "2017-10-25T15:23:57Z")

</div>

> [@Niels\_Dekker](#):
>
> I still think it should be OK to directly use the data from GetOutput(0) as input to the DiscreteGaussianImageFilter, especially because the input parameter is a pointer-to-const, and the instance of DiscreteGaussianImageFilter is only a locally used object.

Unfortunately, the pipelining [is not `const` correct](https://github.com/InsightSoftwareConsortium/ITK/blob/master/Modules/Core/Common/include/itkImageToImageFilter.hxx#L70-L72) and modification may still occur.

> [@Niels\_Dekker](#):
>
> When the function has returned, the DiscreteGaussianImageFilter and its output are gone. Right?

Yes.

This also brings up another possible area for performance optimization – if the DiscreteGaussianImageFilter can be re-used, its output will not get allocated and deallocated repeatedly.

> [@Niels\_Dekker](#):
>
> Do you still think that something like Image::Graft or PipelineMonitorImageFilter should be added in this specific case? I’m asking also because the unit tests now just appear to run successfully. Can you show me a test that would fail on my patch at [http://review.source.kitware.com/#/c/22747/](http://review.source.kitware.com/#/c/22747/) ?

Unnecessary pipeline updates for this filter are likely not covered by the tests and will need manual attention.

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [October 25, 2017, 3:42pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/9 "2017-10-25T15:42:26Z")

</div>

@matt.mccormick Thank you for your informative replies 🙂

Is itk::DiscreteGaussianImageFilter known to modify its input? If so, wouldn’t that be a bug of DiscreteGaussianImageFilter?

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [October 25, 2017, 3:50pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/10 "2017-10-25T15:50:23Z")

</div>

You may want to look at the [ITK Softwareguide](https://itk.org/ITKSoftwareGuide/html/Book1/ITKSoftwareGuide-Book1ch8.html#x47-1340008.3) information about how the pipeline is executed. In should when update is called on a filter the update is processed all the way up the connected filters to ensure everything in the pipeline is up to date. For this case we don’t want that to happen. We want to run the DiscreteGaussian on just the “output” disconnected from the filter that generated it.

To test this cases would require complicated construction of pipelines, updates, and then modification of components of the pipeline. We generally rely on best practices for this type of thing.

Hope that helps.

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [October 26, 2017, 9:35am UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/11 "2017-10-26T09:35:09Z")

</div>

As it appears less trivial than I expected to avoid the extra copying of GetOutput(0) (my patch [http://review.source.kitware.com/#/c/22747/](http://review.source.kitware.com/#/c/22747/)), I just posted a patch of GetCircles(n) on a different PERF issue (which does not include my proposed fix to avoid the copying). Please have a look and tell me what you think:

[http://review.source.kitware.com/#/c/22748](http://review.source.kitware.com/#/c/22748)  
It avoids redundant iterative searches for the maximum in the Hough Transform output image, by calling MinimumMaximumImageCalculator::GetIndexOfMaximum(), instead of GetMaximum().

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [October 26, 2017, 6:17pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/12 "2017-10-26T18:17:56Z")

</div>

@blowekamp You wrote at [http://review.source.kitware.com/#/c/22748/1](http://review.source.kitware.com/#/c/22748/1)

> What happens if the image is empty?

When an empty image is passed as input to HoughTransform2DCirclesImageFilter, GetCircles() throws an exception. It already did so long before I started patching the function. Example:

```
const auto emptyImage = itk::Image<int>::New();
const auto filter = itk::HoughTransform2DCirclesImageFilter<int, int>::New();
filter->SetInput(emptyImage);
filter->Update();
filter->GetCircles(); // throws itk::InvalidRequestedRegionError.

```

This behavior may not be very elegant, but it doesn’t matter much to me, because it doesn’t seem to make much sense to pass an empty image to the filter. Moreover, this behavior has been like that for a very long time. I could even reproduce it on ITK 4.6.0.

> or [what happens if] more circle are requested than exist?

For a non-empty input image, even when you ask for more circles than exist, you just get the number of circles you’re requesting! Again, GetCircles() already did behave like that long before I started patching. For example:

```
const auto image = itk::Image<int>::New();
const auto filter = itk::HoughTransform2DCirclesImageFilter<int, int>::New();

image->SetRegions({ 1, 1 });
image->Allocate(true);

filter->SetInput(image);
filter->SetNumberOfCircles(42);
filter->Update();
const auto numberOfFoundCircles = filter->GetCircles().size();

```

Here ‘numberOfFoundCircles’ is 42, just like the requested number of circles. I don’t think that’s very nice, but it’s the way it’s always been. At least I can reproduce it with ITK 4.6.0. None of my proposed PERF patches change this behavior.

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [October 31, 2017, 3:56pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/13 "2017-10-31T15:56:47Z")

</div>

Thank you all for having accepted my patch to avoid redundant iterative searches for maxima, in GetCircles(n), [https://itk.org/gitweb?p=ITK.git;a=commit;h=f74a599e140e2ae4c28716ed48853299b4abb8ba](https://itk.org/gitweb?p=ITK.git;a=commit;h=f74a599e140e2ae4c28716ed48853299b4abb8ba)

I just submitted another patch to avoid unnecessary memory allocation and copying of pixel data from GetOutput(0), in GetCircles(n). It uses the Graft method suggested here by @blowekamp Please review: [http://review.source.kitware.com/#/c/22760/](http://review.source.kitware.com/#/c/22760/)

It could replace my original patch for that particular issue (which hasn’t been accepted so far), which directly passes a pointer from GetOutput(0) to the gaussianFilter: [http://review.source.kitware.com/#/c/22746/](http://review.source.kitware.com/#/c/22746/) (I still think either of the two patches just work fine.)

---

<div class="post-metadata">

**Author:** ![dzenanz](https://discourse.itk.org/user_avatar/discourse.itk.org/dzenanz/32/1093_2.png) [@dzenanz](https://discourse.itk.org/u/dzenanz)\
**Post date:** [October 31, 2017, 7:50pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/14 "2017-10-31T19:50:21Z")

</div>

Thanks for contributing @Niels_Dekker!

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [November 3, 2017, 10:16am UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/15 "2017-11-03T10:16:08Z")

</div>

Thank you all for having accepted my patch to avoid unnecessary allocation and copying of pixel data in GetCircles(n), [https://itk.org/gitweb?p=ITK.git;a=commit;h=d207d2598ae47f296943a899e6de2d8806bb2f69](https://itk.org/gitweb?p=ITK.git;a=commit;h=d207d2598ae47f296943a899e6de2d8806bb2f69)

I just submitted a patch to remove the apparently obsolete parameter (unsigned int n) from the function. Please review: [http://review.source.kitware.com/#/c/22766/](http://review.source.kitware.com/#/c/22766/)

Could it be that this parameter (n) was originally meant to allow the user to specify the number of requested circles? Currently, it doesn’t seem to be useful anymore.

---

<div class="post-metadata">

**Author:** ![matt.mccormick](https://discourse.itk.org/user_avatar/discourse.itk.org/matt.mccormick/32/7_2.png) [@matt.mccormick](https://discourse.itk.org/u/matt.mccormick)\
**Post date:** [November 3, 2017, 10:45am UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/16 "2017-11-03T10:45:31Z")

</div>

Thanks for the contributions, @Niels_Dekker ! ☀ ✨

I added a review to the new patch.

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [November 6, 2017, 5:59pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/17 "2017-11-06T17:59:57Z")

</div>

Thank you all for having accepted my patch to remove the obsolete parameter (n) from GetCircles(), [https://itk.org/gitweb?p=ITK.git;a=commit;h=63a51c8d493785fb44cb424b0ca4a08c4e96a21f](https://itk.org/gitweb?p=ITK.git;a=commit;h=63a51c8d493785fb44cb424b0ca4a08c4e96a21f)

I just submitted a patch to ensure that the function returns an empty list of circles, when a user has explicitly called filter-\>SetNumberOfCircles(0). Please review:  
[http://review.source.kitware.com/#/c/22772/](http://review.source.kitware.com/#/c/22772/)

FYI With previous ITK releases (\<= ITK v4.12.2), filter-\>GetCircles() would typically return one _or more (!)_ circles, when filter-\>SetNumberOfCircles(0) was called. Which seems very counter-intuitive to me.

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [November 9, 2017, 5:53pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/18 "2017-11-09T17:53:36Z")

</div>

@dzenanz Thanks for having reviewed and merged my latest proposed GetCircles() patch, _“BUG: HoughTransform GetCircles() should avoid circles with accumulator \<= 0”_ , [https://itk.org/gitweb?p=ITK.git;a=commit;h=28962733](https://itk.org/gitweb?p=ITK.git;a=commit;h=28962733)

I would like to mention that I think the bug fix is in accordance with the original intent of the function, as it originally tested on a variable called ‘found’, to check whether it should still continue searching for circles. However, it appeared that ‘found’ was always _true_, when it was tested:

> <https://github.com/InsightSoftwareConsortium/ITK/blob/v4.12.2/Modules/Filtering/ImageFeature/include/itkHoughTransform2DCirclesImageFilter.hxx#L287>

Anyway, ‘found’ is removed already:  
[https://itk.org/gitweb?p=ITK.git;a=commit;h=bc34f7e57433a5e8bc44b315f3f0596f032c026b](https://itk.org/gitweb?p=ITK.git;a=commit;h=bc34f7e57433a5e8bc44b315f3f0596f032c026b)

---

<div class="post-metadata">

**Author:** ![Niels\_Dekker](https://discourse.itk.org/letter_avatar_proxy/v4/letter/n/9d8465/32.png) [@Niels\_Dekker](https://discourse.itk.org/u/Niels_Dekker)\
**Post date:** [November 10, 2017, 2:54pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/19 "2017-11-10T14:54:48Z")

</div>

My latest commit [https://itk.org/gitweb?p=ITK.git;a=blobdiff;f=Modules/Filtering/ImageFeature/test/itkHoughTransform2DCirclesImageTest.cxx;h=dca39bdb63a6eec8094c845e1f90a43de09a4027;hp=709ba8efc4a56d1bd352f7779fcc6a233d824d24;hb=28962733;hpb=014b1245feb3dd10d1c5a5fdd56d8f69ddaeb850](https://itk.org/gitweb?p=ITK.git;a=blobdiff;f=Modules/Filtering/ImageFeature/test/itkHoughTransform2DCirclesImageTest.cxx;h=dca39bdb63a6eec8094c845e1f90a43de09a4027;hp=709ba8efc4a56d1bd352f7779fcc6a233d824d24;hb=28962733;hpb=014b1245feb3dd10d1c5a5fdd56d8f69ddaeb850) does the following, in itkHoughTransform2DCirclesImageTest.cxx

```
filter->SetInput(image);

for (PixelType pixelValue = 0; pixelValue <= 2; ++pixelValue)
{
  image->FillBuffer(pixelValue);
  image->Modified();
  filter->Update();

  if (!filter->GetCircles().empty())
    // ....            
}

```

It appeared that doing image-\>Modified() was necessary to trigger a filter-\>GenerateData() on each iteration of the for-loop. Right? But then, shouldn’t the image already be marked as modified by image-\>FillBuffer(pixelValue)?

**_Update:_** While doing image-\>Modified() appears necessary to trigger filter-\>GenerateData() on each iteration of the for-loop, filter-\>GetCircles() only actively searches for circles on the first iteration. Is that a bug in the filter? Or should the test also do _filter-\>Modified()_, on each iteration?

---

<div class="post-metadata">

**Author:** ![matt.mccormick](https://discourse.itk.org/user_avatar/discourse.itk.org/matt.mccormick/32/7_2.png) [@matt.mccormick](https://discourse.itk.org/u/matt.mccormick)\
**Post date:** [November 10, 2017, 8:50pm UTC](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350/20 "2017-11-10T20:50:06Z")

</div>

Thanks for the continued contributions, @Niels_Dekker 🙂

quote=“Niels\_Dekker, post:19, topic:350”]  
It appeared that doing image-\>Modified() was necessary to trigger a filter-\>GenerateData() on each iteration of the for-loop. Right? But then, shouldn’t the image already be marked as modified by image-\>FillBuffer(pixelValue)?  
[/quote]

Yes, looking into the implementation of `FillBuffer()`, it does not call `->Modified()` internally. This may be historical, or it may be for performance reasons (we do not check to see if the image is not already filled with the value, so -\>Modified() would not be correct).

> [@Niels\_Dekker](#):
>
> Update: While doing image-\>Modified() appears necessary to trigger filter-\>GenerateData() on each iteration of the for-loop, filter-\>GetCircles() only actively searches for circles on the first iteration. Is that a bug in the filter? Or should the test also do filter-\>Modified(), on each iteration?

Without looking into the details, it could be a bug, or it could be a deliberate performance choice.

[Next page](https://discourse.itk.org/t/hough-transform-2d-circles-image-filter-getcircles-patch/350.md?page=2)
